Программирование в среде Mathcad

Оглавление

6.1. Немного истории

Рис. 6.1. Поиск корня алгебраического уравнения методом половинного деления с использованием функций if и until

6.2. Панель программирования

Рис. 6.2. Панель программирования Mathcad

Рис. 6.3. Численное решение задачи Коши (иллюстрация цикла while)

Рис. 6.4. Налоги США (иллюстрация конструкции «выбор»)

Рис. 6.5. Численное решение задачи Коши (иллюстрация цикла for)

Рис. 6.6. Решение буквенной головоломки USA+USSR=PEACE (иллюстрация цикла с параметром)

6.3. Программа-константа – программа-переменная – программа-функция

Рис. 6.7. Программа-константа

6.4. Программа-скаляр – программа-вектор – программа-матрица

Рис. 6.8. Программа-скаляр

Рис. 6.9. Программа-матрица (пасьянс «Турецкий платок»)

6.5. Рекурсия

Рис. 6.10. Расчет факториала (двусторонняя рекурсия)

Рис. 6.11. Расчет чисел Фибоначчи (двусторонняя рекурсия)

Рис. 6.12. Расчет изящных чисел Фибоначчи (двусторонняя рекуррентность)

Рис. 6.13. Расчет чисел Аккермана

Рис. 6.14. BASIC-программа «Ханойские башни»

6.6. Размерность

Рис. 6.15. Размерность в программе

6.7. Remake

Рис. 6.16. Метод Ньютона I (BASIC): цикл с выходом из середины

Рис. 6.17. Метод Ньютона II: цикл с предпроверкой

Рис. 6.18. Метод Ньютона III: имитация цикла с выходом из середины

Рис. 6.19. Метод половинного деления I (Mathcad)

Рис. 6.20. Метод половинного деления II (Mathcad)

Рис. 6.21. Метод половинного деления III (QBasic)

6.8. Проблема метки ....................................... (English version of text)

Рис. 6.22. Задача о рыбаках и рыбке: «беспрограммное» решение в среде Mathcad

Рис. 6.23. BASIC-программы решения задачи о рыбаках и рыбке

Рис. 6.24. Mathcad-программа решения задачи о рыбаках и рыбке

Рис. 6.25. Работа оператора on error

6.9. Tutti-frutti

6.9.1. Золотое сечение

Рис. 6.26. Поиск минимума методом золотого сечения

6.9.2. Силы Кориолиса

Рис. 6.27. Поиск минимума многомерной функции

Рис. 6.28. Тестирование функции minimum на «четырехведерной» задаче

Рис. 6.29. След при минимизации функции двух переменных

Рис. 6.30. След при минимизации функции трех переменных

6.9.3. Продолжение задачи о краске

Рис. 6.31. Программное решение задачи о краске: оптимизация объема краски

Рис. 6.32. Программное решение задачи о краске: оптимизация стоимости краски

6.9.4. Задача о компьютерах

Рис. 6.33. Решение задачи о компьютерах с помощью функции Maximize

Рис. 6.34. Решение задачи о компьютерах перебором (максимум – количество)

Рис. 6.35. Решение задачи о компьютерах перебором (максимум – стоимость)

6.9.5. Трехсторонняя дуэль

Рис. 6.36. Вспомогательные функции программы «Дуэль»

Рис. 3.37. Функция «Победитель»

Рис. 6.38. Проведение дуэлей

Рис. 6.39. Проведение трехсторонней дуэли (бей в случайного)

Рис. 6.40. Статистические испытания функции rnd на трехсторонней дуэли

6.9.6. По-настоящему оптимальное пожарное ведро (English version of text)

Рис. 6.41. Оптимальный радиус пожарного ведра

Рис. 6.42. Оптимальная высота пожарного ведра

Рис. 6.43. Оптимальный объем пожарного ведра

Рис. 6.44. «Перевернутое» оптимальное пожарное ведро

Рис. 6.45. Проектирование оптимального пожарного ведра

6.10. A и B сидели на трубе

6.11. Открытое письмо пирата в адрес компьютерных изданий                                                                                                                                         (English version of text)

6.11.1. Философско-религиозный аспект проблемы

6.11.2. Общекультурный аспект проблемы

6.11.3. Милицейский аспект проблемы

6.11.4. …Моральный аспект проблемы

Рис. 6.46. Перевод чисел из арабской в римскую систему и наоборот

Рис. 6.47. Работа банкомата

Роман в письмах

6.12. Отладка Mathcad-программ

Рис. 6.48. Окно отладки Mathcad-документа в бета-версии Mathcad 8 Pro

Рис. 6.49. Расчет кпд цикла Ренкина (ручной режим – начало)

Рис. 6.50. Расчет кпд цикла Ренкина (ручной режим – продолжение)

Рис. 6.51. Расчет кпд цикла Ренкина (функция пользователя)

Рис. 6.52. Расчет кпд цикла Ренкина (работа функции пользователя)

Рис. 6.53. Разъятая Mathcad-программа

6.13. Оптимизация Mathcad-программ

Рис. 6.54. Поиск корня методом прямого перебора

Рис. 6.55. Поиск минимума функции методом половинного деления

Рис. 6.56. Поиск минимума функции методом случайного поиска

Рис. 6.57. Чистка цикла от комментария

Рис. 6.58. Замена суммы произведением

Рис. 6.59. Замена произведения возведением в целую степень

Рис. 6.60. Хронометраж вложенных циклов

По достоинству оцененная пользователями «изюминка» шестой версии Mathcad, развитая в последующих версиях, – это встроенный язык программирования[1].

6.1. Немного истории

При работе в среде Mathcad всегда ощущалась потребность в программировании для расширения и совершенствования базового набора математических инструментов – операторов и функций. Искушенные пользователи решали эту проблему тремя путями.

Путь 1. В самых первых версиях Mathcad были[2] две функции (if и until), позволявшие через различные хитрости и трюки реализовывать две основные алгоритмические конструкции – выбор (if) и повторение (until). Хитрить же приходилось из-за неспособности функций if и until иметь в качестве аргументов блок составных операторов. Поэтому для реализации даже несложного алгоритма нужно было подключать механизм вложенных функций и операторов, что нередко превращало программу в настоящую криптограмму, в которой даже сам автор разбирался с трудом.

Вот как выглядит поиск корня уравнения методом половинного деления (рис. 6.1) с использованием функции if и until (автор А.Шевченко). Читатель, забегая вперед, может сравнить «программу» на рис. 6.1 с программой (без кавычек) на рис. 6.20, реализующей практически тот же алгоритм.

Рис. 6.1. Поиск корня алгебраического уравнения методом половинного деления с использованием функций if и until

Кроме «зашифрованности» алгоритма (чего стóят аргументы функции until на рис. 6.1) «беспрограммный» поиск корня имеет и другой недостаток: он приводит к нерациональному использованию ресурсов компьютера – к генерации векторов a и b, у которых нас интересуют только последние (last) элементы: между ними зажат искомый корень (переменная корень)[3].

Операторы if и until позволяют менять естественный порядок выполнения операторов в Mathcad-документе: сверху вниз и слева направо. Кроме того, есть еще два признака программирования: локальные переменные и объединение операторов в операторные блоки.

Путь 2. Версии Mathcad начиная с 4.0 – это полноценные Windows-приложения. При решении конкретной задачи в среде Mathcad можно в статике (через файлы на диске или через Буфер обмена – Clipboard) или в динамике (технология DDE и OLE) перенести данные (скаляр, вектор или матрицу) в среду, например, fortran’а и, используя богатый набор средств вычислительной математики этого языка, решить задачу (этап задачи). В среде Mathcad 7 Pro и 8 Pro эта технология была развита и визуализирована через инструментарий MathConnex (см. приложение 10).

Путь 3. Начиная с пятой версии Mathcad пользователям была предоставлена возможность программирования на языке С и объявления в среде Mathcad новых встроенных функций (операторов). Код этих функций нужно откомпилировать каким-либо 32-разрядным транслятором и прикрепить к среде Mathcad через механизм DLL. Но этот путь с самого начала был тупиковым. Во-первых, Mathcad создавался как инструмент решения широкого класса задач теми, кто не хотел или не умел возиться с классическими языками программирования. При обращении же к языку C получалось, что от чего ушли, к тому и пришли. Во-вторых, тот, кто все-таки переключался из среды Mathcad в среду языка С, как правило, там и оставался, решая всю задачу целиком. В-третьих (вернее, во-вторых с половиной), если кто-то и мог решить свою задачу на языке С, то он обычно не пользовался услугами Mathcad по моральным соображениям, считая это ниже своего достоинства. Но главным недостатком в технологии использования C для расширения возможностей Mathcad является невозможность включения в C-программу богатого математического инструментария Mathcad. Технология написания С-функций описана в приложении 8.

6.2. Панель программирования

С первого взгляда на Mathcad возникает вопрос: почему в него не был встроен какой-либо известный и широко используемый язык программирования, а разработан новый, ни на что не похожий[4]? Электронные таблицы Excel, текстовый редактор Word и базы данных Access (Microsoft Office) используют встроенный BASIC[5], что кажется естественным даже для самых непримиримых противников этого языка. Но после детального знакомства с языком Mathcad удивление сменяется пониманием и даже удовлетворением. Становится очевидным, что в рамки традиционных языков с их программами в текстовом формате невозможно втиснуть богатый набор инструментария Mathcad, который реализован не только и не столько в виде функций, сколько в общепринятом в математике виде[6].

В Mathcad, по сути, не встроен язык программирования, а просто снято вышеупомянутое ограничение на использование составных операторов в теле алгоритмических управляющих конструкций выбора (if) и повторения (until). Кроме того, введено понятие локальной переменной, добавлен цикл с параметром for, операторы досрочного выхода из цикла break и continue, а также оператор досрочного выхода из программы return. Алгоритмические конструкции в среде Mathcad вводятся не традиционным набором через клавиатуру ключевых слов if, then, else, while и т.д., а нажатием одной из кнопок панели программирования (Programming):

Рис. 6.2. Панель программирования Mathcad

Щелчок по одной из этих кнопок создает на дисплее заготовку соответствующей программной конструкции.

Опишем их.

Кнопка  – это команда добавления строки в программу, в тело цикла, в плечо альтернативы и т.д. Этим действием снимается вышеупомянутое ограничение на число операторов во вложенных конструкциях языка:

Было

стало

Вертикальная линия объединяет отдельные операторы в операторный блок с одним входом и одним выходом, который выполняется как единый оператор (один из трех атрибутов структурного программирования). Какое-то подобие операторного блока пользователь Mathcad часто выделяет и в беспрограммном документе, реализуя, например, метод последовательных приближений (см. пункт 6 на рис. 5.1).

Кнопка  – это оператор присвоения значения локальной переменной. На языке Pascal мы пишем А := В + С, на языке BASIC – А = В + С, а на языке Mathcad – А ¬ B + С. Почему? Сначала опять же приходится недоумевать, но потом понимаешь, что без знака «¬» программа превратилась бы в нечто невразумительное, режущее глаз программиста:

A := A := B + C (Pascal),

А = А = В + С (BASIC)[7].

В Mathcad-выражении:

A := A ¬ B + C

все более-менее ясно: локальной переменной A (она в середине между символами «:=» и «¬») присваивается значение суммы двух переменных B и C, значение которых уже задано выше в Mathcad-документе (глобальные переменные). Затем эта сумма передается глобальной переменной A (она слева от знака «:=»).

Простейший пример, показывающий разницу между глобальной и локальной переменной:

Негативное изображение переменной В будет свидетельствовать о том, что ее значение вне программы (В ¬ 3) неопределенно[8]. Благодаря локальным переменным можно создавать объемные Mathcad-документы, поручая разработку отдельных функций и операторов разным программистам и не заботясь о разделении переменных: в разных программах переменные могут совпадать по имени, но при этом они не будут перебегать дорогу друг другу (технология программирования «сверху вниз»). С локальными переменными мы, кстати, сталкивались и ранее: примеры индексы i, j и др. в операторах суммы или произведения (см., например, конец рис. 3.14).

Итак, локальная переменная распространяет свое действие только на программу, а глобальная – на весь документ (на низ документа). Но в среде Mathcad есть инструментарий, позволяющий переменным, пользовательским функциям и операторам проникать и в другие документы, но с их, так сказать, согласия. Представим такую ситуацию. Конкретный пользователь создал функции, которые помогают ему быстро решать задачи в конкретной научно-технической области. Решая очередную задачу, пользователь должен в начале документа записать все нужные для расчета функции. Среда Mathcad предоставляет пользователю и другое решение данной проблемы. В новом документе можно сделать ссылку (Reference) на документ (файл с расширением *.mcd), хранящий нужные пользовательские функции, операторы и переменные. Документ, на который ссылаются, может в данный момент не быть открытым, а просто храниться на диске. После этого к создаваемому документу как бы приписывается сверху еще один документ. Пример ссылки на другой Mathcad-документ можно видеть на рис. 6.29, 6.30 и 6.49.

Нажав на кнопку , мы получим на экране заготовку цикла[9] с предпроверкой – слово while с двумя пустыми квадратиками:

В первый квадратик (правее while) нужно будет записать булево выражение (переменную), управляющее циклом, а во второй (ниже while) – тело цикла, операторы которого будут выполняться, пока булево выражение возвращает значение «Да» (в среде Mathcad – это числовое значение, отличное от нуля). Если в теле цикла более одного оператора (а это основное отличие оператора while от вышеупомянутой функции until), то нужно воспользоваться кнопкой Add Line (см. выше).

Рис. 6.3. Численное решение задачи Коши (иллюстрация цикла while)

На рис. 6.3 представлены программы численного решения дифференциального уравнения методом Эйлера и методом Рунге ¾ Кутты 4-го порядка. Ядро программ – цикл while. Созданные программно функции Euler и RK4 возвращают значение (в случае системы уравнений – вектор значений) неизвестного выражения, являющегося решением обыкновенного дифференциального уравнения (системы). Аргументы функций Euler и RK4: х1 – значение (вектор значений в случае системы) искомого выражения в начале отрезка интегрирования (решается задача Коши), t1 и t2 – интервал интегрирования, n – число шагов интегрирования и f – правая часть дифференциального уравнения (в случае системы f – вектор-выражение). Функции Euler и RK4 протестированы на расчете числа е (численное решение задачи Коши для дифференциального уравнения х’ = х) и на задаче об эпидемии, которая нами уже была решена встроенными средствами Mathcad (см. рис. 5.2) функцией rkfixed. Программой же на рис. 6.3 мы как бы раскрываем алгоритм работы функции rkfixed. Читатель может доработать функции Euler и RK4 так, чтобы они возвращали решение не только в конечной точке интегрирования, но и на всем интервале интегрирования. Так работает встроенная функция rkfixed.

В программах на рис. 6.3 записаны комментарии – названия функций. Mathcad, к сожалению, не имеет стандартных средств комментирования программ, поэтому мы поступили так – записали в текст программы текстовую константу “Метод Эйлера” и “Метод Рунге ¾ Кутты 4-го порядка”. Комментарии в тексте программ компилятором игнорируются[10], но они помогают читающему программу понять, что здесь имелось в виду, почему тут был использован данный оператор, а не другой и т.д. В программе без комментариев через некоторое время не сможет разобраться (а тем более подправить или развить ее) даже автор.

Кнопка  позволяет вводить в программу альтернативу с одним плечом. Так, Pascal-конструкция:

if A > B then C := D

в среде Mathcad будет выглядеть несколько по-арабски (по-еврейски – записана справа налево):

С ¬ D if A > B.

Но если плечо альтернативы – составной оператор, то все встанет на свои места, вернее, будет записано по-китайски (сверху вниз):

Pascal:

if A>B then begin E:=F; F:=G end[11];

Mathcad:

if A>B

E¬F

F¬G

Кнопка  превращает неполную альтернативу в полную.

Pascal:

if A > B then C := D else E := F;

Mathcad:

C ¬ D if A > B

 

E ¬ F otherwise

Но если в плечах полной альтернативы по одному оператору, то можно воспользоваться не оператором (кнопкой) if, а функцией if:

C¬if(A > B, D, F) или if(A > B, C¬D, E¬F)

Понять, почему в Mathcad не было использовано традиционное слово else, можно, если принять во внимание то, что операторы if и otherwise позволяют записать в программах алгоритмическую конструкцию множественное ветвление. Разберем ее на примере задачи о расчете налогов (федеральный налог США с недельного заработка).

Рис. 6.4. Налоги США (иллюстрация конструкции «выбор»)

Функции Tax1 и Tax2 (пункт 1) возвращают налог с холостых и женатых по прогрессивной шкале налогообложения (см. график в пункте 3). В данном примере (и во всех других) без оператора otherwise можно обойтись (сравните окончания функций Tax1 и Tax2). Он необходим в тех случаях, когда булево выражение, объединяющее оставшиеся случаи ветвления, трудно сформировать. Оператор otherwise это гибрид ключевых слов ELSE, ELSEIF и CASE ELSE языка BASIC.

Программы на рис. 6.4 несложно реализовать и без программирования (без операторов if и otherwise), задействовав традиционную Mathcad-функцию if и вкладывая ее саму в себя: if(..., if (..., if(... и т.д. Но программирование функций Tax1 и Tax2 делает их более прозрачными и для понимания, и для редактирования.

В седьмой версии Mathcad появился оператор досрочного прерывания программы, который вводится нажатием кнопки return. Он очень уместен в программе на рис. 6.4 (см. пункт 2): если налогоплательщик мало получает и тем самым освобожден от налога, то нечего и забираться в глубь программы. Кроме того, программой в пункте 2 на рис. 6.4 проиллюстрирована работа текстовой переменной (у нас это S), а также функции error выдачи пользовательского сообщения об ошибке: если к «покрасневшей» функции Tax (последняя строка в пункте 2) подвести курсор, то «выпадет» пользовательское сообщение об ошибке “Укажите правильный статус налогоплательщика”. Дополнительно в функцию Tax на рис. 6.4 введены денежные единицы по принципу «Время – деньги» – см. рис. 1.14.

В программах на рис. 6.4 можно заменить константы и получить функцию для расчета российских налогов. Автор этого не делает по следующим причинам.

Во-первых, за нашей шкалой налогообложения не угнаться. Инфляция с деноминацией и с новой инфляцией делает бессмысленными коэффициенты формул. Кроме того, наши парламентарии считают, что у нас налоги не собираются из-за плохой налоговой системы, в частности, из-за неправильных коэффициентов функции Tax. Но это иллюзии. Налоги у нас не платят в первую очередь из-за того, что люди не хотят отдавать свои деньги неизвестно на что[12]. На больницы, на школы денег нет, а губернатор N-ской области, где эти бедные школы и больницы расположены, еженедельно на своем личном самолете со своей многочисленной свитой летает в Москву. Когда ему говорят, что так делать нельзя, что бюджетные средства в первую очередь должны идти в социальную сферу, то он эти законные претензии называет «дешевым популизмом». Сами же налогоплательщики не желают иметь в качестве посредников таких нечестных людей и стараются отдавать деньги бюджетникам напрямую – собирают деньги на уборку класса, передают конверт с «благодарностью» врачу и т.д. Конечно, это порочная система, но что делать, если люди, призванные распоряжаться нашими деньгами, не могут или не хотят сделать это умно и честно.

Сравнивая нашу шкалу налогов с американской, следует отметить, что в США при больших заработках ставка налога падает с 33 до 28%. Дальновидная политика! В стабильном обществе богатые люди свои доходы не прячут и не проедают, а пускают в дело – расширяют производство, покупают акции и т.д. Кроме того, американская налоговая система нацелена на укрепление семьи. Но мы отвлеклись от основной темы…

Кнопка  вводит в программы цикл с параметром.

Когда заранее известно, сколько раз нужно выполнить какую-то часть программы (тело цикла), то используют не цикл while, а цикл for, в заголовке которого пишут не булево выражение, а параметр цикла и указывают, какие дискретные значения он должен принимать в цикле. Эти значения можно перечислить через запятую (1, 2, 3.7) или указать диапазоном (2.. 100) или вектором (V). В программах на рис. 6.3, кстати, более уместен цикл for с заголовком for t Î t1, t1 +D.. t2, а не цикл while. При этом программы можно будет несколько упростить, убрав операторы t ¬ t1 и t ¬ t + D (см. рис. 6.5).

Рис. 6.5. Численное решение задачи Коши (иллюстрация цикла for)

Вот более занятная иллюстрация цикла for.

Рис. 6.6. Решение буквенной головоломки USA+USSR=PEACE (иллюстрация цикла с параметром)

Программа на рис. 6.6 решает буквенную головоломку USA+USSR=PEACE, где требуется указать, какие цифры скрываются за буквами. В программе три цикла с параметром (A, C и S), которые вложены друг в друга. В программе, не мудрствуя лукаво, можно было записать все семь циклов – по числу неизвестных задачи U, S, A, R, P, E и C. Но тогда перебор (а именно этим способом решается наша головоломка – вспомним «извращения» этюда 3) длился бы нестерпимо долго. Несложный предварительный анализ условий задачи (U ¬ 9, Р ¬ 1, Е ¬ 0 и R ¬ 10 + A) сокращает число циклов до трех и делает время счета приемлемым. Один из основных недостатков языка Mathcad – это невозможность вывода на дисплей промежуточных результатов расчета. А они не только помогают отлаживать программы, но и в ряде случаев просто необходимы при поиске единственно правильного решения из множества возможных (см., например, программы на рис. 6. 34 и 35 с решением задачи о компьютерах). В Mathcad-программах допустима запись вариантов ответов (промежуточных результатов) в матрицу (в вектор), которую после выполнения программы можно просмотреть, что и сделано на рис. 6.6. При этом в матрицу M записываются не только значения числовых переменных, но и текстовые константы[13] (“+”, “=” и др.), делающие ответ более читабельным. Правильный ответ хранится в первом столбце матрицы M. Вернее, в первой строке – матрица у нас транспонируется для большей компактности[14]. Остальные ответы неверны – там разным буквам соответствуют одинаковые числа.

Цикл с параметром в среде Mathcad более гибок, чем его аналоги в языках BASIC или Pascal. Вот еще варианты заголовков циклов с параметром в среде Mathcad, кроме тех, которые показаны на рис. 6.6 (там специально приведены разные варианты заголовков циклов):

for A Î V        (V – вектор)

for A Î 5, 4.7, 8.9, 7.3×10-5

for i Î i1.. i2.

Последний вариант примечателен тем, что переменные i1 и i2 могут принимать любые значения, и необязательно, чтобы i1 было меньше i2. В языках BASIC и Pascal разное соотношение между i1 и i2 требует различного синтаксиса заголовка цикла с параметром:

For i=i1 To i2 или For i=i2 To i1 Step -1                         (BASIC)

for i:=i1 to i2 do или for i:=i2 downto i1do                       (Pascal).

Кнопки  и  позволяют досрочно выходить из циклов while и for, а кнопка  совсем из программы. О них разговор особый (см. раздел 6.7 данной книги). Сейчас же проведем такую аналогию.

Все структурные управляющие конструкции Mathcad можно усмотреть в простой житейской ситуации: потчевание гостей чаем и кофе. Хозяйка проверяет, нет ли на столе пустой чашки (булева переменная, управляющая циклом while), и наполняет ее (тело цикла) чаем или кофе (альтернатива). Добавление в чашку кусочков сахара – новый, вложенный цикл. При разливе чая чашка (стакан) может лопнуть, что прерывает цикл, из которого выходят в конец цикла (break – гости встают из-за стола и занимаются чем-то другим) или в начало цикла (continue – на столе меняется скатерть и чаепитие возобновляется). Третий сценарий: разбитая чашка так расстраивает хозяйку, что вечеринка досрочно заканчивается (return).

Ниже приведены другие примеры программ в среде Mathcad.

Общие замечания. Язык программирования Mathcad по своей идеологии очень похож на язык FRED интегрированного пакета Framework. Говорят, что один из «погорельцев» фирмы Ashton-Tate (разработчика Framework) перешел в фирму MathSoft и приложил руку к созданию языка программирования Mathcad. Внешне же своими вертикальными линиями, фиксирующими вложения конструкций программы и операторные блоки, пакет Mathcad напоминает алгоритмические конструкции книги А.П.Брудно «Программирование в содержательных обозначениях» (М.: Наука, 1968). В свое время я очень увлекался подобными линиями, втискивая программы в рамки структурных диаграмм (см. рис. 6.21, а также книгу «128 советов начинающему программисту». – М.: Энергоатомиздат, 1991). Вертикальные линии программ Mathcad более наглядны (особенно для обучения структурному программированию), чем просто операторные скобки (begin-end на языке Pascal, фигурные скобки языка С, оператор list() языка FRED, конец строки BASIC-программы, круглые скобки математических выражений и т.д.).

Говоря о структурном программировании, нельзя не отметить тот факт, что разработчики языка Mathcad отказались от метки и операторов условного и безусловного перехода к метке как инструмента реализации разветвленных алгоритмов. Для некоторого смягчения этой категоричной позиции и были введены операторы return, break и continue.

6.3. Программа-константа – программа-переменная – программа-функция

Кнопки программирования (см. рис. 6.2) по своей сути дополняют традиционные встроенные операторы (+, -, *, ¸ ...) и функции (sin, cos, log ...), с помощью которых пользователь формирует выражения, значение которых присваивается константам, переменным и функциям пользователя.

Рис. 6.7. Программа-константа

Программу, формирующую константу, подобрать несложно. Но зачем? Константу можно раз и навсегда рассчитать (задать), а потом вставлять результат в Mathcad-документ (константы p, е и др.). Но иногда для лучшего понимания сути константы полезно оставить механизм ее формирования открытым. Программа на рис. 6.7 подсчитывает число, фигурирующее в легенде об изобретателе шахмат, который в награду попросил дать ему такое количество зерна, какое он может положить на шахматную доску с тем, чтобы на первой клетке было одно зернышко (21-1 т.е. 20), на второй – два (22-1), на третьей – четыре (23-1) и т.д. (на новой клетке зерен в два раза больше, чем на предыдущей). На рис. 6.7 подсчитывается не все количество зерен на шахматной доске, а их масса в британских тоннах, не превышающая 100 000 тонн (масса одного зерна принята за 0.3 грамма).

Программы-переменные и программы-функции читатель увидит ниже.

6.4. Программа-скаляр – программа-вектор – программа-матрица

Эта тройка переменных может задаваться, естественно, и программно.

Рис. 6.8. Программа-скаляр

Программа на рис. 6.8 возвращает скалярное значение – номер элементов (iopt) векторов X, Y и Z при котором... В этюде 3 мы искали домик на дачном участке, где следует устроить, например, продовольственный ларек. Критерий выбора – минимальная сумма расстояний от ларька до всех остальных домиков. Теперь (рис. 6.8) ларек у нас уже космический, а задача трехмерная. На рис. рис. 3.12 подобная задача решалась без привлечения инструментов программирования.

Программы на рис. 3.12 и 6.8 довольно примитивны. Но читатель может их развить, заменив, например, декартову систему координат на географическую, где вектор X будет хранить значения долготы, а вектор Yшироты объектов. Тогда задача может свестись к поиску места, например, для вертолетной площадки, обслуживающей геологов или нефтяные скважины, и стать не только более сложной, но и более реальной[15].

Рис. 6.9. Программа-матрица (пасьянс «Турецкий платок»)

Рассмотрим эту особенность на такой занимательной задаче.

Очень часто, решая ту или иную проблему, мы оказываемся в шкуре буриданова осла. Задача может иметь два альтернативных решения, как две охапки сена слева и справа от упомянутого животного. Все доводы «за» и «против» уравновешены. Как в этом случае поступить? Ехать или не ехать в командировку? Покупать или не покупать еще один винчестер? Поистине, гамлетовские вопросы задает нам жизнь!

Некоторые в таких ситуациях бросают монетку, другие загадывают мужчину или женщину и смотрят в окно, ожидая, кто первый появится. Но все это ненаучные методы. Монетка может куда-нибудь закатиться, а по улице как назло за целый час только кошка и пробежит...

Есть проверенный столетиями метод принятия подобных решений. Достаточно разложить пасьянс. Сошелся – решение принято и все сомнения прочь. Можно подыскать дополнительные доводы в его пользу, и начать воплощать в жизнь. Пасьянс психологически нас на это настраивает.

Но принять решение подобным образом иногда бывает трудно, так как не всегда под рукой есть колода карт, да и не совсем удобно раскладывать их на рабочем месте. Но это можно сделать и на экране дисплея. В среде Windows, например, есть игры-пасьянсы («Солитер» и «Косынка»), но мы придумаем что-нибудь новенькое, а, главное, более занимательное и поучительное – разложим в среде Mathcad старинный пасьянс «Турецкий платок». На это есть три причины:

1.Чтобы лучше освоить программную среду, нужно постараться решить в ней задачу, для этого крайне неподходящую. Да, это своего рода программистское извращение, но – см. этюд 3.

2.В детстве каждый нормальный человек, наигравшись, ломал игрушку, чтобы посмотреть, как она устроена. Посмотрим и мы, как тасуется колода и раскладывается пасьянс.

3.По традиции гадать на картах и раскладывать пасьянсы разрешается только в святки[16]. Наш пасьянс можно считать числовой головоломкой, которую позволительно решать круглый год.

Mathcad-документ (см. рис. 6.9) позволяет разложить пасьянс «Турецкий платок» по следующим правилам. Из одной перетасованной колоды в 52 листа выкладывают картинкой вверх пять рядов по 10 карт в каждом. Последние две карты кладут в шестой неполный ряд на любое место, как правило, к первому и второму столбцам. Требуется распустить этот «платок», снимая из разных столбцов за один ход по две нижние одинаковые карты – тройки, дамы, тузы и т.д.

Для снятия карт нужно скопировать правую часть оператора П = ... (саму матрицу) на свободное место, подвести курсор к нужной текстовой константе (к карте), щелкнуть по левой кнопке мыши и нажать клавишу Delete. Вместо числа появится пустой квадратик.

Из разложенного пасьянса сняты две двойки. Теперь можно снять две восьмерки, два короля или две десятки (вопрос – какие из трех открытых). После этого откроются новые карты. Если удастся снять все 52 карты, то это означает, что в командировку все-таки ехать придется, а винчестер покупать надо.

Составление программы, формирующей матрицу П (раскладка пасьянса) – прекрасное и, что не менее важно, занимательное средство изучения таких базовых понятий линейной алгебры, как вектор и матрица. Так, при формировании матрицы П транспонируется матрица Масть (она ставится «на попа» – матрица с одной строкой превращается в матрицу с одним столбцом, то есть в вектор). Далее с помощью функции stack составляется новая нерастасованная колода карт, где одна отсортированная масть идет за другой (вектор Колода). Затем в цикле с параметром (for...) с помощью цикла while[17] и функции rnd идет формирование перетасованной колоды – вектора Тасованная_колода, который в конце программы двойным циклом с двумя параметрами (for... for...) складывается слоями в матрицу П.

Программу, формирующую матрицу П, можно развить: заставить программу отбраковывать явно нерешаемые раскладки – такие, например, где в одном столбце оказались три или даже четыре одинаковые карты. Еще одна тупиковая ситуация – две пары карт крест накрест закрывают друг друга. Это будет хорошим упражнением, закрепляющим навыки работы с «матричными» операторами и функциями в среде Mathcad. А вот более сложное задание читателю: доработать программу так, чтобы она сама раскладывала пасьянс, либо на худой конец сообщала, что его можно решить, просто снимая снизу первые подвернувшиеся одинаковые открытые карты. Более умная стратегия подразумевает выбор карты из трех или четырех одинаковых открытых карт.

Кроме линейной алгебры, наша программа затрагивает и другие интересные разделы математики – теорию вероятностей, статистику (см. функцию rnd, генерирующую псевдослучайные числа). Интересный вопрос: можно ли составить программу, высчитывающую вероятность сходимости того или иного пасьянса? Считается, что пасьянс «Солитер», входящий в стандартную поставку Windows, раскладывается при любых начальных раскладках. Но это только гипотеза…

Часто бывает так, что человек прекрасно делает то, чему он учился играючи и с большим удовольствием: ходит, говорит, плавает, катается на велосипеде и т.д. и т.п. Автор, например, задолго до школы научился считать, играя в карты: валет – двойка, дама – тройка и т.д. И сейчас, обращаясь к своим студентам, не устает повторять, что главное, что нужно получать от учебы, – это не знания, не практические навыки, а... удовольствие. Не получая радости от учебы, от повседневного труда, человек тратит свою жизнь впустую... Например, если тяжело идет освоение линейной алгебры – расслабьтесь и постарайтесь получить удовольствие.

Начинать изучение векторов и матриц (массивов данных) в курсе программирования (информатики) можно со знакомства со встроенными функциями и операторами конкретной программной среды. А можно раскладывать пасьянсы.

Как уже отмечалось ранее, переменные в Mathcad могут быть локальными, самообъявляющимися в программах (как, например, переменные Случайное_число, Колода, Карта, Столбец и Ряд в программе на рис. 6.9). Значение локальных переменных пропадает по выходу из программы. Разработчики языка Mathcad посчитали лишним обязательное объявление переменных до их использования (как это делается при работе с языком Pascal, например). Наверное, переменные не объявляются из-за того, что они все однотипные[18]. Но необъявление переменных может приводить к ошибкам, которые трудно выявить, так как язык Mathcad не имеет средств отладки (debugging). Ввел программист в программу переменную dаy, а через пару операторов написал dey (что по произношению более соответствует английскому слову day (день); можно умудриться написать и dаy, где вторая буква будет из русского алфавита) – программа выдает неверный ответ. Опечатки в программе часто бывают намного страшней в плане отладки, чем ошибки алгоритма. Кроме локальных и глобальных переменных, значения которых заданы вне программы и автоматически в нее проникают, в среде Mathcad есть и системные (предопределенные) переменные и константы. Пример – числа e и p, значение которых определено самой системой (математикой), а не пользователем (см. приложение 4).

Мы уже не первый раз используем буквы кириллицы в именах переменных и функций. В программе на рис. 6.9 впервые все переменные прописаны по-русски. Pro и Contra этого приема.

Pro[19]:

Полные имена переменных (Столбец, Ряд вместо i, j) делают программу более простой для понимания, но более сложной для написания (рекомендуется длинные переменные писать один раз, а потом копировать в нужных местах). Конечно, можно было написать и английские термины в качестве имен переменных, но они будут выглядеть чужеродными в пасьянсе, программу которого для русскоязычного читателя написал человек, считающий себя русским. Да и автор, честно говоря, не знает, как будет по-английски «Масть», «Колода». Лезть же в словарь не с руки. Проще написать Мast, Коloda. Проще, да некрасиво (см. ниже).

Contra:

· Русские имена переменных порождают «смешенье языков французского с нижегородским»: for Столбец?! Правильнее и грамотней писать for Солбца[20] (для Столбца); на многих программистов русское имя объекта программирования (файла, переменной, функции и т.д.) действует как красная тряпка на быка[21].

·В латинском и русском алфавитах многие буквы (например, а, с) совпадают по написанию. Из-за этого в программе могут оказаться переменные, одинаковые для человека, но разные для Mathcad.

·Выбор для переменных шрифта с окончанием Cyr приводит к перекодировке символов. Из-за этого, например, может пропасть восклицательный знак в факториале и др.

6.5. Рекурсия

Рекурсивная функция – это такая функция, которая вызывает сама себя в момент ее создания[22]. Рекурсия – очень мощный и удобный инструмент решения задач. Так, например, один из самых быстрых алгоритмов сортировки массива использует рекурсию. Вычислить детерминант квадратной матрицы также помогает рекурсия и т.д.

Языки программирования в своем развитии обычно проходят три стадии:

1. Рекурсия невозможна.

2. Рекурсия не разрешена, но применяется по принципу: «Если нельзя, но очень хочется, то можно». Так, на старых версиях языка BASIC рекурсия реализовывалась через оператор ON N GOTO, передающий управление программой на N-ю строку.

3. Рекурсия разрешена.

Mathcad вторую стадию проскочил (условно проскочил – это мы еще отметим, разбирая рис. 6.13).

И вот уже трещат морозы

И серебрятся средь полей...

(Читатель ждет уж рифмы розы;

На вот, возьми ее скорей!)

Читатель ждет уж примеров рекурсии в среде Mathcad? Скорее всего, нет. Традиционные примеры (розы-морозы) ему оскомину набили. Но мы попробуем что-нибудь свеженькое. Например, двустороннюю (ретроспективную) рекурсию.

Как запомнить число e (основание натурального логарифма) с девятью цифрами после запятой? Очень просто – две целых семь десятых плюс два раза Лев Толстой – 2.718281828, то есть к числу 2.7 нужно приписать два раза год рождения классика (1828). Остается самая малость – запомнить, в каком году родился Лев Толстой, или, на худой конец, сообразить, что это случилось в прошлом веке[23], чтобы вспомнить хотя бы три знака числа e после запятой: 2.718. Ретроспектива, обращенная в XIX век, поможет запомнить довольно-таки точное значение одной из фундаментальных констант математики.

Как запомнить, что факториал нуля равен не нулю (типичная ошибка), а единице? Очень просто. Нужно применить ретроспективный метод поиска факториала числа: сообщить машине факториал какого-либо положительного числа N (5! = 120, например) и то, что факториал предыдущего числа N-1 равен факториалу первого (N!), разделенному на N. Факториал пяти (120) – это такая же тривиальная истина, как и то, что Лев Толстой родился в XIX веке, а грубая оценка числа е – 2.7.

Рис. 6.10. Расчет факториала (двусторонняя рекурсия)

Работая по программе с двусторонней рекурсией, показанной на рис. 6.10, можно не только правильно определить факториал нуля (единица), но и получить факториалы отрицательных (?!) чисел. Только нужно обучить этому машину – заложить в программу двустороннюю рекурсию для поиска факториала на всем целочисленном диапазоне[24]. «Двусторонность» здесь проявляется в том, что факториалы ищутся не только справа, но и слева от пяти.

Описывая в этюде 5 модель финансовой пирамиды, мы упомянули числа Фибоначчи, которые связаны с условными кроликами:

Поколение

...

4

5

6

7

8

9

10

11

...

Число кроликов

...

3

5

8

13

21

34

55

89

...

Приведенный ряд специально начат не с традиционного места (первое поколение), а с четвертого поколения (три кролика), для того чтобы задать читателю вопрос, подобный тому, который стоял в задаче о факториале: «Чему равно минимальное число кроликов в популяции – каково наименьшее число Фибоначчи?» Нормальный ответ, приводимый во всех учебниках, – ноль. Но не будем спешить и напишем программу с двусторонней рекурсией, взяв за базовые числа Фибоначчи не традиционную пару 0 и 1, а 13 и 21 (седьмое и восьмое поколения – см. рис. 6.11).

Рис. 6.11. Расчет чисел Фибоначчи (двусторонняя рекурсия)

Ряд кроликов Фибоначчи в «отрицательных поколениях» зеркально отображает значения в «положительных поколениях», но с переменным знаком.

Числа Фибоначчи в наше время широко применяются в вычислительной математике, в том числе и для иллюстрации рекурсии, как, например, в нашей книге. Кроме того, метод Фибоначчи используется для поиска минимума. Частный случай метода Фибоначчи – метод золотого сечения (см. рис 6.26): пара смежных чисел Фибоначчи при N, стремящемся к бесконечности, соотносится по золотому сечению.

Рис. 6.12. Расчет изящных чисел Фибоначчи (двусторонняя рекуррентность)

Использование рекурсии для поиска чисел Фибоначчи – это стрельба из пушки по воробьям. Намного эффективнее рассчитывать подобные числа в цикле, рекуррентно. На рис. 6.12 представлена программа, по которой ищутся, если так можно выразиться, изящные (fine) числа Фибоначчи[25], где базой будут тройка, семерка[26] и туз (11). Следующим изящным числом Фибоначчи будет 21 (3+7+11, тоже красиво – вспомним знаменитую карточную игру). Предыдущим числом окажется 1 (11-7-3, опять неплохо, если принять во внимание, что сестра таланта не только краткость, но и простота). Остальные изящные числа Фибоначчи, пользуясь программой на рис. 6.12, рассчитать несложно – главное тут суметь дать им «изящное» толкование.

В программе на рис. 6.12 еще раз подчеркнуто, что размещение нескольких операторов на одной строке – это недокументированный прием. Если такая «упакованная» программа будет давать неверный результат, то фирма MathSoft за это ответственности не несет. Мы же будем считать такую программу «заархивированной» и не занимающей много места в книге. Такую программу при вводе в компьютер требуется «разархивировать».

Другой резон размещения нескольких операторов на одной строке лежит в сфере образования. Автор просит своих студентов операторы, не находящиеся в причинно-следственной связи, писать на одной строке – A ← 1 B ← 2, например. Оператор же, который опирается на предыдущий (предыдущие), следует писать внизу:


A ← 1 B ← 2
C ← A + B

Так можно имитировать параллельные вычисления на однопроцессорной машине: считается, что операторы на одной строке выполняются одновременно, а записанные столбиком – последовательно.

Задание читателям на закрепление пройденного: сделать программу на рис. 6.11 рекуррентной, а на рис. 6.12 – рекурсивной[27].

Рис. 6.13. Расчет чисел Аккермана

Есть более крепкий орешек – числа Аккермана, зависящие уже от двух переменных (см. рис. 6.13 с двойной рекурсией). В среде Mathcad числа Аккермана можно рассчитать только для значений аргументов m и n, находящихся недалеко от нулей («каботажное плавание»). Расчет, например, значения Akk(4, 6) через некоторое время аварийно прерывается – см. рис. 6.13. Рекурсия – это когда программист, сокращая текст программы, перекладывает свои проблемы на плечи машины, которой приходится генерировать длинный ряд новых локальных переменных. Отсюда и сбои. Выход из положения – замена рекурсии на рекуррентность (цикл), что автор и предлагает сделать читателям по отношению к числам Аккермана.

Для закрепления темы рекурсии приводим текст BASIC-программы, решающей известную головоломку «Ханойские башни»[28] (рис. 6.14):

DefInt N

DefStr X-Z

Declare Sub PUTDISK (N%, X$, Y$, Z$)

 

Input "Число дисков в пирамиде"; N0

            PUTDISK N0, "A", "B", "C"

End

 

Sub PUTDISK (N%, X$, Y$, Z$)

DefInt N

DefStr X-Z

If N = 1 Then

                        Print X; "-"; Z

            Else

                        PUTDISK N - 1, X, Z, Y

                        Print X; "-"; Z

                        PUTDISK N - 1, Y, X, Z

            End If

End Sub

Рис. 6.14. BASIC-программа «Ханойские башни»

Суть головоломки. Имеется три стержня, на первый из которых (у нас в программе на рис. 6.14 он маркирован как A) нанизаны диски на манер детской пирамидки: самый большой диск внизу – самый маленький наверху. Предлагается переложить эти диски на второй стержень (C), беря их по одному и не кладя большой диск на маленький. Для временного складирования разрешается использовать третий диск (B). Программе на рис. 6.14 достаточно сообщить только число дисков в пирамиде N. После запуска программа будет возвращать порядок перекладки дисков:

N=2: A-B, A-C и B-C (три хода)

N=3: A-C, A-B, C-B, A, В-A, B-C и, наконец, A-C (семь ходов)

N=4: …(15 ходов) и т.д.

Число перестановок в общем случае равно 2N-1. Задача с N дисками легко сводится к задаче с N-1 дисками, а задача с N-1 дисками легко сводится к задаче с N-2 дисками и т.д. до задачи с двумя дисками, которая решается просто – A-C (см. на рис. 6.14 фрагмент программы If N = 1 Then Print X; "-"; Z). Отсюда и рекурсия в программе на рис 6.14.

Задание читателям[29] – переписать BASIC-программу на рис. 6.14 для Mathcad. Подводный камень: BASIC-программа оператором Print выдает результат из подпрограммы. В языке Mathcad это сделать невозможно – там допустимо сначала полностью заполнить матрицу, и только потом вывести ее на дисплей.

По легенде тибетские монахи уже несколько тысячелетий перекладывают 64 золотых диска, нанизывая их на алмазные стержни. Когда головоломка будет решена и на стержне C окажутся все диски, наступит конец света. Спасает нас лишь то, что при 64 дисках для решения головоломки потребуется:

Это без учета ложных ходов и времени, необходимого на ручной или компьютерный расчет порядка перестановки дисков.

6.6. Размерность

По знаменитой формуле Н.Вирта программа – это сумма алгоритма и структуры данных. Алгоритм программы в среде Mathcad задается нажатием десяти кнопок на панели программирования (рис. 6.2), отвечающих за циклы, альтернативы и прочее. Структура данных в среде Mathcad также проста. Там есть только вещественные переменные двойной точности, которые могут превращаться в комплексные или целочисленные, группироваться в векторы и матрицы (простые и вложенные), принимать, если надо, текстовые значения.

Рис. 6.15. Размерность в программе

Тип числовой переменной в среде Mathcad, как уже было отмечено в этюде 1, в какой-то мере заменяется размерностью хранимой величины, что очень удобно в инженерных расчетах. По программе на рис. 6.15 рассчитывается площадь треугольника (пункт 1). Аргументами функции Площ_треуг могут быть величины с разной размерностью длины (метры – m, сантиметры – cm, дюймы – in). Система Mathcad сама в них разберется, сделает нужные пересчеты и выдаст правильный результат в выбранной пользователем системе единиц (кг-м-с, г-см-с, СИ или британская).

Система Mathcad, кроме того, ведет контроль размерностей и не позволяет складывать, например, метры с килограммами или секундами (см. соответствующее встроенное сообщение об ошибке в конце пункта 1 на рис. 6.15).

Функция в среде Mathcad, как уже отмечалось, может возвращать несколько значений, объединенных в вектор. Программно заданная пользовательская функция в пункте 2 на рис. 6.15 возвращает значение периметра и площади треугольника. Но если пользователь захочет сделать размерными аргументы, чтобы функция вернула ему значение периметра и площади треугольника с соответствующими размерностями (пункт 3), то его ждет неудача. При этом будет выдано дезинформирующее сообщение об ошибке: «Несоответствие единиц измерения». Пользователь будет думать, что он складывает метры с килограммами, как в пункте 1. Но причина в другом – вектор в среде Mathcad может хранить переменные только одной размерности. Из-за этого нам уже пришлось отказаться от размерностей при решении задачи о равновесии балки – сравните рис. 1.15 и 1.16.

Можно заставить функцию выдавать две величины не сразу, а попеременно – в зависимости от значения дополнительного аргумента (пункт 4): если i = “Периметр”, то функция Параметры_треуг возвращает периметр треугольника, если i = “Площадь”, то – площадь. Но и здесь работа с размерностями будет приводить к сбоям – см. пункт 5 на рис. 6.15. Функция Параметры_треуг всегда возвращает размерность переменной из последней строки программы.

Ошибок в среде Mathcad, как и в любой другой программной среде, достаточно. Автор акцентирует внимание на этой ошибке по двум причинам. Во-первых, автор когда-то убил уйму времени, отлаживая программу, подобную программе на рис. 6.15, и не понимая, в чем суть ошибки. Во-вторых, дал об этом знать разработчикам Mathcad, но в восьмой версии эта ошибка почему-то не была исправлена. Кстати, об ошибках…

Считается, что по-настоящему красивая женщина («чертовски красивая») непременно должна иметь внешний дефект (ошибку Природы), небольшой, но сразу бросающийся в глаза: вздернутый нос, родинка, веснушки... Такие «украшения» лишний раз напоминают о том, что это не богиня, от которой лучше держаться подальше, не бездушная «кукла восковая», а земная женщина. Вот хрестоматийный пример: Наталья Николаевна Пушкина (урожденная Гончарова) – петербургская красавица, которая тем не менее чуть-чуть косила[30]. А вот другой пример – Шекспир воспел «смуглую леди сонетов» в те времена, когда белизна лица считалась непременным атрибутом женской красоты.

Слово «чуть-чуть», только что промелькнувшее в тексте, напоминает о кратком, но точном определении художественного вкуса: «Искусство – это чувство меры». Рафинированное произведение искусства, созданное на основе чистых канонов, находится как бы в неравновесном состоянии. Маленький щелчок («глюк» в программе, родинка на лице красавицы или ее легкое косоглазие, кривая колокольня в Пизе, корявый автограф в углу картины или темный штрих в биографии художника или программиста[31], на худой конец) сталкивает эту шаткую балансирующую конструкцию либо в чулан поделок (кич), либо в сокровищницу шедевров.

А вот еще пример, поворачивающий проблему на новую грань, где пересекаются плоскости формы и содержания. Сергей Довлатов в своих записках упоминает об известном профессоре-филологе с такими косыми глазами, что с ним трудно было общаться – непонятно, в какой глаз нужно смотреть. Этот профессор, прикрывая рукой левый глаз, говорил собеседнику: «Смотрите в правый. На левый не обращайте внимания. Левый – это дань формализму». Хорошо дурачиться, создав предварительно целую филологическую школу – ошибки простительны только в гениальных программах.

Если читатель увидит опечатки или даже ошибки в этой книге, то автор просит, во-первых, сообщить об этом автору, а, во-вторых, перечитать то, что написано выше.

Работа с размерностями вообще требует особой аккуратности. Вот хороший совет при работе в среде Mathcad. Вводить в Mathcad-документ новую переменную лучше оператором «m=» (вывод значения), а не оператором «m:=» (ввод значения). Этим пользователь проверяет лишний раз, не занята ли уже переменная m хранением заданной ранее величины. В Mathcad 7 и 8 этот прием не обременителен, так как в среде этих версий оператор «m=» автоматически (Smart Operator) превращается в оператор «m:=», если переменная m свободна от хранения чего-либо.

Предпроверку переменных особо можно рекомендовать в расчетах с использованием размерностей физических величин[32]. В этом режиме (а он включается по умолчанию) предопределенными (системными) будет огромное число «популярных» переменных (A, c, C, F, g, H, J, K, L, m, N и т.д. – см. приложение 7), хранящих единичные значения физических величин (сила тока, скорость, заряд, емкость, ускорение, индуктивность, энергия, температура, длина, количество вещества и т.д.). В таком расчете «невинное» выражение «m:=3» развалит весь стройный порядок единиц измерения: вместо метров появится черт знает что.

6.7. Remake

В седьмой части этюда автор расскажет в стиле римейк об особенностях языка Mathcad.

Почему римейк? Во-первых, см. предисловие. Во-вторых, у автора сохранился файл с текстом статьи «Turbo Pascal 7.0. Взгляд со стороны» (КомпьютерПресс, № 7’93), которая и подвергается римейку (remake – переработка). В-третьих, язык Mathcad, как и язык Pascal, оказался окутан паутиной старых догм[33] структурного программирования, о которых писалось в упомянутой статье. Это делает римейк не только простым, но уместным и естественным.

Итак, remake.

Попробуем на простых примерах показать, что ввод в язык Mathcad операторов break, continue и return (см. выше) – только полшага в сторону повышения гибкости управляющих конструкций этого языка программирования.

Рис. 6.16. Метод Ньютона I (BASIC): цикл с выходом из середины

На рис. 6.16 приведена BASIC-программа поиска корня алгебраического уравнения методом Ньютона (касательных). Почему мы начали с языка BASIC, ведь этюд посвящен языку программирования Mathcad? Дело в том, что язык BASIC кроме традиционной тройки циклов (цикл с предпроверкой, цикл с постпроверкой, цикл с параметром) имеет и универсальный цикл с выходом из середины: Do [...] If ... Then [...] Exit Do [...] Loop. Эта конструкция наряду с другими преимуществами, о которых будет сказано ниже, позволяет реализовывать алгоритмы в их естественной последовательности. Так, в программе на рис. 6.16 объявляются функции пользователя (анализируемое уравнение y и его производная dy), запрашивается значение начального приближения к корню x и задается значение погрешности TOL. После этого организуется цикл, но не традиционный, а с выходом из середины. В цикле, следуя естественному порядку алгоритма Ньютона, рассчитывается новое приближение к корню (x1), и если оно отстает от предыдущего не более чем на величину заданной погрешности[34], то (Then) задача считается решенной (Exit Do). Если нет, то ведется подготовка к новому приближению (x = x1), а цикл повторяется (Loop).

При реализации на языке Mathcad этот несложный алгоритм обрастает «архитектурными излишествами», так как его приходится реализовывать функцией и «запихивать» в прокрустово ложе цикла while – см. рис. 6.17.

Рис. 6.17. Метод Ньютона II: цикл с предпроверкой

Цикл с предпроверкой (цикл while) требует, чтобы булево выражение заголовка было определено еще до входа в цикл. А этого нет при поиске корня методом Ньютона. Приходится до входа (и для входа) в цикл писать x1 ¬ x + 2 × TOL. Подобным образом лгут детям (а машина тоже в каком-то смысле дитя), заставляя их что-то делать. Строку x1 ¬ x + 2 × TOL можно уподобить стартеру двигателя внутреннего сгорания, работающего, кстати, как и программа на рис. 6.17, циклически. Вот какими аллегориями (дитя, двигатель) обросла наша простенькая программа из-за того, что в языке Mathcad нет цикла с выходом из середины. На рис. 6.17 можно отметить и другую ненатуральность программы – постановку телеги впереди лошади: в цикле сначала приходится готовиться к новому приближению (x1 ¬ x), хотя еще не ясно, понадобится оно или нет, а только потом проводить его.

Операторы break, continue и return, введенные в Mathcad, призваны вернуть программе на рис. 6.17 ее естественность, но...

Рис. 6.18. Метод Ньютона III: имитация цикла с выходом из середины

BASIC-конструкция Do ... Loop (см. рис. 6.16) на рис. 6.18 превратилась в конструкцию while 1 ..., которую на латинский язык можно перевести как «ad calendas greaces»«до греческих календ». Здесь, как и в программе на рис. 6.17, пришлось идти если не на обман, то на натяжку: «выполняй, пока рак на горе не свистнет».

Оператор continue отличается от оператора break тем, что передает управление не в хвост, а в гриву (начало) цикла[35]. Но в документации и в файлах помощи Mathcad нет примеров, обосновывающих использование оператора continue. Не смог придумать их и автор.

История с вводом в Mathcad операторов break и continue и return подтверждает старую истину о том, что «нет ничего практичнее хорошей теории». И вот почему.

Вышеприведенный анализ циклов на языке Mathcad имеет не только сугубо практический, но и чисто теоретический аспект. Как известно, набор управляющих конструкций любого структурного языка ведет свою родословную от основной структурной теоремы Дейкстры, объявившей войну меткам: «Алгоритм любой сложности можно реализовать, используя только цикл while и альтернативу». Автор потратил уйму времени и сил на поиск доказательства этой теоремы в статьях или книгах, но так ничего и не нашел. А вот показать, что данная теорема не верна, можно в два счета – см. рис. 6.19 и рис. 6.20. Эти программы решают уже известную нам задачу о корне алгебраического уравнения, но другим методом – методом половинного деления. Его алгоритм – простейшая иллюстрация теоремы Дейкстры: цикл (while) приближения к корню, в которой вложена альтернатива (if ... ). Если корень правее центра интервала a-b, то к нему (к центру) подтягивается левый край (a ¬ x), если нет – правый (b ¬ х).

Рис. 6.19. Метод половинного деления I (Mathcad)

В программе на рис. 6.20 альтернатива программы на рис. 6.19 заменена на два цикла while, операторы тела которых попеременно выполняются либо раз, либо ни разу, что регулируется булевой переменной Flag.

Рис. 6.20. Метод половинного деления II (Mathcad)

Кроме того, в программе на рис. 6.20 проведена чистка цикла, в теле которого значение анализируемой функции рассчитывается всего раз. В программе на рис. 6.19 это делалось два раза. Второе изменение в программе на рис. 6.21 по сравнению с программой на рис. 6.19 состоит в том, что не используется функция Хевисайда. Букву Ф у нас принимают не за греческую букву «фи», а за русскую букву «эф» и делают ошибку, которую трудно понять и поэтому тяжело исправить. Функцию Хевисайда заменяет произведение значений анализируемой функции на концах вилки. Булева операция And в программе на рис. 6.20 вызывается не в виде функции And(..., ...), а древовидным оператором.

Рис. 6.21. Метод половинного деления III (QBasic)

В аналогичной BASIC-программе (на рис. 6.21 она вписана в структурную диаграмму) также обошлись без альтернативы. Более того, удалось избавиться и от переменной-диспетчера Flag, заменив два цикла while на один цикл, но с двумя выходами из середины – одним условным, а вторым безусловным.

Весь фокус программ на рис. 6.20 и 6.21 в том, что альтернатива – это средство ускоренного «путешествия» по алгоритму только в одну сторону (сверху вниз и слева направо), а цикл – в обе. Отсюда и ненужность (в теоретическом плане, конечно, а не в практическом[36]) альтернативы. Цикл Do [...] If ... Then [...] Exit Do [...] Loop можно считать гибридом цикла и альтернативы.

Доказательством теоремы Дейкстры может служить факт, что до сих пор не было случая, когда задуманный алгоритм нельзя было бы реализовать, используя только цикл и альтернативу[37]. Если альтернативу исключить, то основная структурная теорема должна звучать так: «Алгоритм любой сложности можно реализовать, используя только цикл». Вот это-то теоретическое положение вводом операторов break, continue и return подсовывает задним числом язык программирования Mathcad под свой фундамент. Обращаю внимание на несовершенный вид глагола – «подсовывает», а не «подсунул» – цикл с выходом из середины на языке Mathcad осуществим через насилие над циклом while (рис. 6.18). При этом приходится писать в заголовке цикла какую-нибудь тривиальную истину: «Волга впадает в Каспийское море».

Теорему Дейкстры следует «понизить в звании» и называть леммой, то есть вспомогательной теоремой, служащей для доказательства основной.

Здесь мы вернулись к спорам, бушевавшим лет 30 назад. Операторы break, continue и return, введенные в язык Mathcad, дали нам повод напомнить о них. Эти операторы по принципу «и вашим и нашим» примирили сторонников и противников оператора перехода к метке.

6.8. Проблема метки
         (
English version of text)

Проблему метки, вернее, проблему избавления от метки, мы рассмотрим на примере решения старинной английской задачи о рыбаках и рыбке:

«Три рыбака легли спать, не пересчитав и не поделив улова. Ночью один из рыбаков проснулся и решил уйти, забрав свою долю. Но число рыб не делилось на три. Тогда он, не долго думая, выбросил одну рыбку, а из остатка забрал треть. Второй и третий рыбак поступили аналогичным образом – ушли по-английски и по-джентельменски, выбросив по одной рыбке и оставив спящим товарищам четное число рыб. Спрашивается, какое минимальное число рыб в улове отвечает условию задачи».

Пусть читатель сначала попробует решить эту задачу без компьютера. Компьютер же мы привлечем к этой работе для двух целей. Во-первых, на задаче о рыбаках и рыбке мы рассмотрим некоторые методы структурирования программ в среде Mathcad – методы освобождения программ от меток и «втискивания» их в узкие рамки структурных управляющих конструкций, описанных выше (см. рис. 6.2). Во-вторых, мы покажем, что задача о рыбаках и рыбке до сих пор решалась неправильно...

Эту задачу в среде Mathcad можно решить, не прибегая к средствам программирования.

Рис. 6.22. Задача о рыбаках и рыбке: «беспрограммное» решение в среде Mathcad

На рис. 6.22 показано, как задача решается методом последовательных приближений – задается первое приближение к ответу (50 рыб), а затем от этого числа отнимается по единице до тех пор, пока убывающий улов не будет представлять собой целочисленный ряд: было 25 рыб (искомый ответ задачи), первый рыбак выбросил одну, забрал треть и оставил товарищам 16 рыб (по 8 каждому); второй рыбак (не зная, что первый ушел) оставил 10 рыб, а третий – 6. Задача решена, но с применением «ручной» работы, состоящей в наблюдении за значениями переменной Улов и в изменении (уменьшении на единицу) значения переменной Ответ. (Блоки операторов, фиксирующих действие трех рыбаков, можно не дублировать, как это сделано на рис. 6.22. Достаточно уменьшать[38] значение переменной Ответ и следить за значениями переменной Улов).

Попробуем автоматизировать поиск ответа в задаче о рыбаках и рыбке.

‘ 1. Исходная неструктурированная Basic-программа

Input "Предположение"; Ответ

label: Улов = Ответ

            For Рыбак = 1 To 3

                        Улов = Улов – 1

Улов = Улов - Улов / 3

                        If Улов > Int(Улов) Then Ответ = Ответ - 1: Goto label

            Next

Print "Ответ "; Ответ; “рыб”

 

‘ 2. Первый шаг структурирования - разбег

Input "Предположение"; Ответ

Ответ = Ответ + 1 ‘ Шаг назад

label: Ответ = Ответ - 1 ‘ Шаг вперед

            Улов = Ответ

            For Рыбак = 1 To 3

                        Улов = Улов – 1

Улов = Улов - Улов / 3

                        If Улов > Int(Улов) Goto label

            Next

Print "Ответ "; Ответ; “рыб”

 

‘ 3. Второй шаг структурирования – ввод признака

Input "Предположение"; Ответ

Ответ = Ответ + 1

label: Ответ = Ответ – 1

Улов = Ответ

            Поделили = "да" ’ Признак дележа улова

            For Рыбак = 1 To 3

                        Улов = Улов – 1

Улов = Улов - Улов / 3

                        If Улов > Int(Улов) Then Поделили = “нет”

            Next

If Поделили = “нет Goto label

Print "Ответ "; Ответ; “рыб”

 

‘ 4. Третий шаг структурирования – отказ от метки

Input "Предположение"; Ответ

Ответ = Ответ + 1

Do ’ Начало цикла с постпроверкой

            Ответ = Ответ – 1

Улов = Ответ

Поделили = "да"

            For Рыбак = 1 To 3

                        Улов = Улов – 1

Улов = Улов - Улов / 3

                        If Улов > Int(Улов) Then Поделили = “нет”

            Next

Loop Until Поделили = "да" ’ Конец цикла

Print "Ответ "; Ответ; “рыб”

Рис. 6.23. BASIC-программы решения задачи о рыбаках и рыбке

На рис. 6.23 представлены четыре Basic-программы, решающие задачу о рыбаках и рыбке в автоматическом режиме: оператор Input запрашивает первое приближение (те же 50 рыб, к примеру), а оператор Print выдает ответ – 25 рыб. В первой BASIC-программе один к одному реализован алгоритм «ручного» расчета: как только в теле цикла с параметром (три последовательных ухода рыбаков) переменная Улов обретает дробный «хвостик» (встроенная BASIC-функция Int этот «хвостик» обрезает; ее Mathcad-аналог – функция floor), то (Then) предположение уменьшается на единицу (Ответ = Ответ - 1), а управление программой передается к оператору, помеченному меткой (Goto label). Прежде чем эту программу перевести на язык Mathcad, ее нужно освободить от метки[39]. И не только потому, что в арсенале средств программирования Mathcad нет метки и операторов условного и безусловного перехода к метке, но по другим причинам, не связанным с Mathcad. В нашей коротенькой программе-безделушке (пункт 1 на рис. 6.23) метка вполне уместна и естественна, но если программа с метками разрастается, то в ней становится трудно разбираться и ее практически невозможно отлаживать и расширять. Программа, как справедливо подчеркивают адепты структурного программирования, становится похожа на спагетти: вытаскиваешь (вилкой) блок операторов для отдельной отладки или компиляции, а к нему намертво привязаны нити (макаронины) Goto-переходов. Кроме того, такую программу невозможно создавать группой разработчиков (технология снизу вверх). Первые реализации языка Pascal совсем не имели меток, так как этот язык разрабатывался Н.Виртом в первую очередь для обучения студентов структурному программированию. Метка появилась только в поздних версиях этого языка. Так от детей в период, когда они учатся жить (выживать!), прячут спички.

Первый шаг структурирования BASIC-программы на рис. 6.23 – это превращение конструкции:

If Улов > Int(Улов) Then Ответ = Ответ - 1: Goto label

в оператор условного перехода к метке:

If Улов > Int(Улов) Goto label

Это сделать несложно (см. пункт 2 на рис. 6.23), применив в программе технику разбега спортсмена перед прыжком: шаг назад от черты-метки (Ответ = Ответ + 1) и разбег (Ответ= Ответ - 1). Структурирование программы, как правило, несколько усложняет алгоритм: «За все нужно платить!», «Красота требует жертв!» и т. д.

Второй шаг структурирования – это вытаскивание оператора безусловного перехода из тела цикла For. Для этого в программу (см. пункт 3) вводится вспомогательная булева переменная-признак Поделили, а в теле цикла оператор условного перехода к метке заменяется на оператор «альтернатива с одним плечом» (одна из основных структурных управляющих конструкций). Сам же оператор условного перехода «сползает» вниз. После этого в программе «вырисовывается» еще одна основная структурная управляющая конструкция – цикл с постпроверкой, который в третьем варианте на рис. 6.23 реализован через метку и оператор условного перехода к метке. После этого программу наконец-то можно совсем освободить метки, реализуя алгоритм через цикл с постпроверкой, в тело которого вписан цикл for, а в него ¾ альтернатива с одним плечом (пункт 4).

После всех этих манипуляций четвертый вариант BASIC-программы можно один к одному переписать для Mathcad – см. рис. 6.24. Придется только оформить ее в виде функции пользователя: в языке Mathcad нет операторов Input и Print[40]. Их аналоги в среде Mathcad (операторы := и =) работают, увы, только вне программ.

Рис. 6.24. Mathcad-программа решения задачи о рыбаках и рыбке

На рис. 6.24 показаны вызовы функции Ответ при различных значениях предположений (50, 24, минус 3 и даже минус 30 рыб). Английский физик Поль Дирак придумал не только античастицы, но и «антирыбы»: он сказал, что задача о рыбаках и рыбке решалась неправильно (25 рыб). Правильный ответ – минус две рыбы (плюс две антирыбы): выбрасываем одну – остается минус три, забираем треть – остается минус две и так до бесконечности. Наше компьютерное решение задачи показывает, что и Дирак ошибался: «Поль, ты не прав!» Условию задачи отвечает бесконечный ряд чисел (назовем его «рыбный ряд Дирака») с шагом 27.

Чтобы не прослыть совсем уж полным педантом (программистом-занудой), можно в конец цикла for на рис. 6.24 вставить оператор break if Поделили = ”нет”, прерывающим выполнения цикла for. Если рыбаков будет не трое, а больше (тридцать три рыбака, например – задача для читателя), то этот прием существенно ускорит работу программы (см. главку «Оптимизация Mathcad-программ»).

Можно еще усложнить задачу, заставив любое количество рыбаков выбрасывать или подлавливать любое количество рыб.

Задачу о рыбаках и рыбке можно решать другим способом – перебором с другого конца: задать не начальное число рыб в улове, а предположить, что последний рыбак оставляет две рыбы (меньше не может быть), и увеличивать их число на единицу, если условия задачи не выполняются. Задача будет решаться быстрее, но минус двух рыб, а, тем более, минус 29 рыб мы не получим: «Keep if simple, stupid! – Делай это проще, дурачок!» Человеку психологически трудно спуститься к отрицательным числам в ответе, машина же делает это спокойно, без всяких предрассудков. Не дает отрицательного ответа и аналитическое решение задачи – поиск целочисленных корней одного уравнения с двумя неизвестными.

Остается рассказать о последней кнопке  на панели программирования Mathcad 8 Pro. Нажатие на нее приводит к появлению на дисплее заготовки инфиксного оператора обработки ошибок с двумя операндами:

Суть оператора проста: если при выполнении правого операнда возникнет ошибка, то выполняется левый операнд. Этот оператор позволяет реализовывать в Mathcad-программах метод проб и ошибок.

Автору, как только он познакомился с оператором on error, сразу захотелось испробовать его на простом примере:

Но оказалось, что объявленная таким образом функция y(х) возвращает нуль, а не единицу при x = 0. Дело в том, что система Mathcad, оптимизируя произведение, выдает нуль, если первый сомножитель равен нулю. Функцию y(х) нужно переписать по другому:

но и эта запись не совсем правомочна. Проще записать:

Оператор on error незаменим в тех случаях, когда ошибку сложно локализовать, что иллюстрирует пример на рис. 6.25.

Рис. 6.25. Работа оператора on error

Здесь графически решается неравенство: функция f(x) возвращает нуль не только тогда, когда логарифм меньше единицы, но и тогда, когда делается попытка взятия логарифма от неположительного числа. Можно, конечно, решить квадратное уравнение и обойти ошибку функцией или оператором if, но на рис. 6.25 мы все сделали проще.

6.9. Tutti-frutti

Ниже приводится ряд программ, написанных на языке Mathcad и решающих самые разнообразные задачи (tutti-frutti по-итальянски – всякая всячина): оптимизация, головоломка, статистика, теория вероятностей...

6.9.1. Золотое сечение

Программа на рис. 6.26 ищет минимум функции одной переменной методом золотого сечения[41]. В ней используется вспомогательная функция с именем Зол_Сеч, позволяющая отрезок a-b (отрезок неопределенности) поделить в золотом соотношении. Вывод этой функции через решение уравнения золотой пропорции средствами символьной математики (см. этюд 7) представлен в пункте 1 рис. 6.26.

Рис. 6.26. Поиск минимума методом золотого сечения

Аргументы функции мин_З_С:

· имя функции, у которой ищется минимум (y[42]);

· левое значение интервала неопределенности (a);

· правое значение интервала неопределенности (b).

Функция мин_З_С возвращает значение аргумента, при котором функция y имеет минимум[43]. Он ищется циклически. Условие завершения цикла – сужение интервала неопределенности до величины, меньшей или равной значению TOL. В цикле интервал неопределенности делится в золотом соотношении, что позволяет при новом приближении к максимуму использовать данные предыдущего приближения. Это вытекает из свойств золотого сечения и позволяет в цикле вычислять только одно значение функции, а не два, как при использовании метода половинного деления (см. рис. 6.55).

Функция мин_З_С протестирована на поиске объема пожарного ведра максимальной вместимости (задача из этюда 2). Функция, связывающая объем ведра с углом вырезки заготовки, задана также программными средствами (а не вложением вспомогательных функций, как на рис. 2.2). С помощью программы поиска минимума ищется максимум за счет изменения знака анализируемой функции. Отсюда можно предположить, что одна из новых встроенных в Mathcad 8 функций ¾ Minimize или Maximize ¾ лишняя. Но это не так – в оптимизационных задачах с ограничениями (см., рис. 2.9 и 2.10) заменить поиск минимума на поиск максимума не так просто.

6.9.2. Силы Кориолиса

На рис. 6.27 представлена созданная с помощью программирования функция minimum, возвращающая координаты точки минимума функции многих переменных (ее имя – аргумент y) и начинающая поиск от начальной точки приближения (вектор x). Алгоритм поиска минимума прост. От точки начального приближения по всем координатам делается шаг D (третий аргумент функции minimum). В новых местах[44] вычисляются значения минимизируемой функции. Туда, где функция имеет минимальное значение, делается переход, данная точка становится новой точкой приближения к минимуму, а все вышеописанные действия («ощупывание» функции вблизи точки приближения) повторяются. Если окажется, что вблизи новой точки приближения все новые значения функции увеличиваются, то шаг поиска (D) уменьшается вдвое, а все действия повторяются. Поиск заканчивается, когда значение D становится меньше TOL (системная переменная Mathcad, регулирующая точность вычислений).

Рис. 6.27. Поиск минимума многомерной функции

Функция minimum протестирована (рис. 6.28) на решении «четырехведерной» задачи (см. этюд 2, где решались «одно-«, «двух-» и «трехведерные» задачи – поиск оптимального посекторного раскроя круглой заготовки для изготовления одного, двух и трех пожарных ведер с максимальным суммарным объемом). Показано, что четвертое ведро лишнее (как, кстати, и третье – см. рис. 2.7).

Рис. 6.28. Тестирование функции minimum на «четырехведерной» задаче

Алгоритм спуска к минимуму, заложенный в программу на рис. 6.27, ¾ простой и без всяких оптимизирующих хитростей. Так, например, при очередном приближении к минимуму лишний раз рассчитывается значение анализируемой функции в предыдущей точке. Если анализируемая функция простая и ее значение высчитывается быстро, то это повторение мало влияет на общее время поиска минимума. Но что будет, если функция достаточно сложная? Предлагаем читателям доработать программу на рис. 6.27 и исправить отмеченный недостаток. Программа должна запоминать значение анализируемой функции в предыдущей точке приближения и использовать его в новом приближении. Это, кстати, заложено в метод золотого сечения (см. рис. 6.26). А вот более сложное задание. При поиске минимума функции двух переменных мы «перекрещиваем» точку очередного приближения, как бы благословляя успех поиска:

Более оптимальная стратегия может требовать «охвата» очередной точки не крестом, а равносторонним треугольником со стороной D (симплекс-метод; при минимизации функции трех переменных точка помещается внутри тетраэда и т. д.):

Кроме того, неплохо треугольник (либо звезду Давида или даже пятиконечную звезду – новое задание читателю) при каждом шаге приближения к минимуму ориентировать в пространстве случайным образом, растягивать его вдоль одной из вершин. Этим также можно добиться более оптимальной стратегии поиска минимума.

Описанные ухищрения можно перенести и на задачу с n переменными оптимизации (n-мерная иудейская или пятиконечная звезда!). Все это будет хорошим заданием читателям. Поиск и испытание алгоритмов оптимизации относится к одному из разделов вычислительной (прикладной) математики. В данной книге мы только чуть-чуть заглянули в него.

Читатель может отметить еще одну «неоптимальность» программы на рис. 6.27. Она генерирует не только вектор значений переменных, где функция минимальна, но и целую матрицу М с «историей» поиска, которую потом приходится транспортировать (МТ), определять номер ее последнего столбца (L) и вычленять его (М<L-1> – см. рис. 6.28). Но перегрузка программы на рис. 6.27 не была напрасна. Как уже отмечалось ранее, программирование в среде Mathcad лишено средств отладки. Простейшее, но тем не менее очень эффективное средство отладки программ – наблюдение за промежуточными результатами. А как раз это в среде Mathcad делать невозможно. И все же – если нельзя, но очень хочется, то можно. Программа, приведенная на рис. 6.27, успешно справляется с довольно-таки сложными задачами (см., например, рис. 6.28). Но если ей подсунуть совсем уж простую функцию – тестовую функцию Розенброка из этюда 3, то при определенных начальных приближениях программа на рис. 6.27 зациклится – ответа от нее не дождешься. В чем тут дело? Ответить на этот вопрос поможет некоторая модернизация программы: прервать ее работу можно не только по условию D £ TOL, но и по дополнительному условию, например, n > 30. После того как число шагов приближения n превысит 30, можно будет просмотреть след поиска минимума функции Розенброка или иной другой (задание читателю).

Рис. 6.29. След при минимизации функции двух переменных

На рис. 6.29 показан след поиска минимума функции х8+y6.

Наполните ванну водой, бросьте туда перышко или какой-нибудь другой легкий предмет и выдерните пробку. Перышко сначала будет более-менее спокойно двигаться к отверстию (первый график на рис. 6.29), а затем закрутится в водовороте (второй график). Наш метод поиска минимума можно назвать не просто методом наискорейшего спуска, а методом наискорейшего спуска воды. Жидкость не просто спускается водоворотом, она всегда вращается в одну сторону. Если даже раскрутить ее в противоположном направлении, то, преодолев насилие, она снова потечет по часовой стрелке. Говорят, что это физическое явление через силы Кориолиса связано с вращением Земли: на экваторе вода в ванне не закручивается, но севернее или южнее экватора она приобретает «правый» (как на рис. 6.29) или «левый» уклон. Автор проверил эту гипотезу: он переслал по е-mail файл с задачей коллеге в Австралию. Все подтвердилось: линии траектории спуска стали закручиваться в другую сторону – против часовой стрелки. Интересно, как они себя поведут на Северном или на Южном полюсах? С водой там все ясно, она вообще не будет течь – замерзнет. А вот что будет с кривыми? К сожалению, у автора нет коллег в Арктике и Антарктике.

Читатель, наверное, уже догадался, что его разыгрывают – этот материал был опубликован в апрельском выпуске одного компьютерного журнала[45].

Но самое смешное в этой истории то, что траектории спуска, показанные на рис. 6.29 в Австралии на самом деле стали закручиваться в другую сторону. Все объяснилось довольно просто: при передаче файла на линии произошел маленький сбой и в программе на рис. 6.27 вместо строки for i Î ORIGIN .. L - 1 появилась строка for i Î L - 1 .. ORIGIN[46]. Вот и все объяснение. Но виноваты в этом все те же силы Кориолиса – магнитные диски винчестеров на серверах и маршрутизаторах Южного полушария вращаются несколько иначе, чем на Северном полушарии. Отсюда и сбои, выявить которые довольно сложно, так как при контрольной обратной пересылке файла ошибка исправляется по принципу «минус на минус дает плюс»[47].

Рис. 6.30. След при минимизации функции трех переменных

На рисунке 6.30 показан объемный след при оптимизации функции трех переменных x8 + y6 + z4.

В целях все той же отладки можно отслеживать ход поиска минимума функции четырех и более переменных, отображая проекции следа на отдельные плоскости по паре взятых переменных.

6.9.3. Продолжение задачи о краске

Применение средств программирования позволяет по-новому решить нашу задачу о краске (см. рис. 3.11 в этюде 3). При единственности решений, оптимизирующих либо объем, либо стоимость краски, разливаемой в барабаны двух типов, можно найти не одно, а ряд решений, где объем меньше максимального не более, чем на 2%, а при поиске максимума цены – на 0.5%.

Рис. 6.31. Программное решение задачи о краске: оптимизация объема краски

Рис. 6.32. Программное решение задачи о краске: оптимизация стоимости краски

Обе программы выдают по шесть вариантов решений, лежащих вблизи максимумов объема и цены краски. Эти решения пересекаются: варианты 6/15 (шесть маленьких и пятнадцать больших) и 13/13 просматриваются в обоих решениях.

6.9.4. Задача о компьютерах

Для производства четырех видов компьютеров (С1, С2, С3 и С4) имеются[48] комплектующие пяти видов. Необходимо спланировать выпуск компьютеров (найти значение переменных С1, С2, С3 и С4) так, чтобы:

·      их число было максимально;

·      их стоимость была максимальна.

Исходные данные по задаче сведены в таблицу:

компьютера

Стоимость
(у. е.)

Число единиц комплектующих, идущих на один компьютер

 

 

1

2

3

4

5

1

600

1

0

4

0

3

2

2500

1

0

8

0

8

3

25 000

0

1

0

4

15

4

60 000

0

1

0

8

64

Есть комплектующих:

100

20

500

100

1200

Подобная задача реально стоит перед людьми, собирающими компьютеры «на коленках» отверточным способом: челноки привезли детали: 1 и 2 – это, к примеру, центральные процессоры двух типов, 3 и 4 – микросхемы памяти, а 5 – платы связи с периферией; компьютеру нужно, конечно, и многое другое, но это другое (корпуса, винчестеры) имеется в избытке. Из комплектующих нужно собрать компьютеры, максимизируя вышеотмеченные целевые функции.

Рис. 6.33. Решение задачи о компьютерах с помощью функции Maximize

На рис. 6.33 приведено решение этой задачи линейного программирования с помощью встроенной Mathcad-функции Maximize[49]. Целевые функции (ЦФ) в Mathcad-документе записаны двумя способами: общее число компьютеров (ЦФ1) как функция четырех аргументов-скаляров и стоимость компьютеров (ЦФ2) как функция одного аргумента-вектора. Это позволяет решить задачу двумя способами: «скалярным» (решение 1 по числу компьютеров) и «векторным» (решение 2 по стоимости компьютеров). Второе решение удобно тем, что его методика позволяет легко корректировать задачу: ввод новых переменных и новых ограничений требует лишь внести изменения в векторы КЦФ (стоимость компьютеров) и k (ресурсы по комплектующим) и в матрицу kC (расход комплектующих). Да, вторая методика лучше, но второе решение никуда не годится: как понимать дробные решения ¾ как призыв поставлять компьютеры россыпью или не полностью укомплектованными? Если с первым решением все ясно (можно изготовить максимум 120 компьютеров; какой стоимостью и в каком раскладе ¾ мы еще об этом поговорим), то второе нужно дорабатывать: цифры плана выпуска компьютеров нужно округлять. Дело в том, что функция Maximize не умеет возвращать решение задачи целочисленного линейного программирования. Не совсем умеют ее решать и специально созданные для этих целей программы ¾ вспомним, как в среде Excel решалась задача о краске (см. главку «Как автор продавал программы» в этюде 3).

Целочисленное решение, максимизирующее число компьютеров, получилось, можно сказать, случайно. Так же «случайно» был получен целочисленный план перевозки телевизоров со вкладов в магазины и план выпуска стульев из этюда 2.

Ничего не остается делать, как прибегать к методу перебора, плюсы и минусы которого рассмотрены в этюде 3.

Рис. 6.34. Решение задачи о компьютерах перебором (максимум – количество)

Рис. 6.35. Решение задачи о компьютерах перебором (максимум – стоимость)

На рис. 6.34 и 6.35 приведено решение задачи о компьютерах методом перебора. В программах реализовано три вложенных цикла – по числу типов компьютеров, максимальное количество которых подсчитать несложно: 62 штуки – С2 (лимит по комплектующему №3), 20 – С3 (по №2) и 12 – С4 (по №4). Важное замечание! В программах фиксируются все планы выпуска компьютеров, максимизирующие их число (120 штук) или стоимость (875 600 у.е. – эту цифру можно определить предварительно, отыскивая один план из многих возможных). Что дал перебор и чего не дал бы другой метод решения задачи целочисленного линейного программирования? Оказывается, планов выпуска 120 штук компьютеров целых 156. Можно выпускать не только 100 первых и 20 третьих типов компьютеров (решение, найденное на рис. 6.33), но и 75, 25, 15 и 5. Стоимость компьютеров при этом увеличивается с 560 000 у.е. до 782 500 (см. последний, 155-й столбец).

Функция Maximize «спрятала» от пользователя оптимальный план. Более того, если на рис. 6.33 в качестве начального приближения дать оптимальное первое приближение (75, 25, 15 и 5), то Maximize упорно вернет старый результат – 100, 0, 20 и 0 компьютеров.

На рис. 6.34 выведены первые и последние столбцы матрицы План, содержащей все 156 планов выпуска компьютеров общим числом 120, но с разной стоимостью: от 560 000 у.е. (100, 0, 20 и 0 компьютеров разного типа) до782 500 у.е. (75, 25, 15 и 5 компьютеров).

Еще более интересное решение получается при максимизации стоимости компьютеров (рис. 6.35). Дело в том, что при решении задач линейного программирования, как правило, оперируют только неотрицательными значениями переменных (см. ограничение С ³ 0 на рис. 6.33). Но при С1<0 задача может быть сформирована с таким дополнением: «Купи на стороне компьютеры первого типа, разбери их, а дефицитные детали пусти на производство более дорогих машин». Стоимость компьютеров даже с учетом расходов на приобретение машин первого типа может быть выше, чем при традиционном решении. Так и получилось – см. рис. 6.35: матрица План содержит только 2 столбца с «нормальным» решением (1-й столбец: 1, 60, 5 и 10 компьютеров и 4-й столбец: 1, 56, 3 и 11 компьютеров). Максимальная стоимость (883 800 у.е.) получается тогда, когда на стороне покупается 27 компьютеров первого типа.

Метод перебора становится незаменим в том случае, когда задача о компьютерах перестает быть линейной. А это случается, если поставщик комплектующих делает скидку при покупке оптом. Такая динамика изменения цен нами статистически обработана – см. рис. 4.15.

6.9.5. Трехсторонняя дуэль

А теперь автор представляет на суд читателя свою любимую задачу – задачу о трехсторонней дуэли. Вот ее условия.

Сэм, Билл и Джон договорились сразиться на дуэли втроем по следующим правилам:

·жеребьевка определяет, кто стреляет первым, вторым и третьим;

·дуэлянты располагаются на одинаковых расстояниях друг от друга (по углам равностороннего треугольника);

·обмениваются выстрелами по очереди, определенной жребием, пока двое не будут убиты;

·очередной стреляющий может стрелять в любого из живых.

Известно, что Сэм – снайпер и никогда не промахивается с данной дистанции, Билл поражает мишень в 80% случаев, а Джон – в 50%. Какова наилучшая стратегия для каждого из участников и каковы вероятности их выживания, если они следуют оптимальным стратегиям?

В этой дуэли у Сэма и Билла могут быть две тактики поведения. Нулевая – это когда стреляющий ничего не знает о меткости соперников и целит в первого подвернувшегося. Первая – когда дуэлянту известно о том, кто как стреляет, и он метит в соперника с наивысшими стрелковыми качествами в надежде остаться tête-à-tête с наихудшим стрелком.

Джон может следовать и второй тактике. Чтобы получить наивысшие шансы выйти победителем из дуэли, он должен намеренно стрелять в воздух, пока двое его соперников живы. Ведь очередной стреляющий будет бить не в него, а в более меткого противника. После того как Сэм или Билл будет убит, Джон должен показать все, на что он способен. В такой ситуации его шансы выжить составляют 50%, если он остался наедине с Сэмом, и еще больше ¾ если с Биллом.

Участник дуэли, прежде чем выстрелить, должен, во-первых, определить самого меткого соперника, в которого нужно стрелять, руководствуясь первой тактикой поведения. Для этого предназначена функция Самый_меткий (см. пункт 2 на рис. 6.36), возвращающая номер противника с наивысшими стрелковыми качествами. В ней перебором всех участников дуэли (цикл for) учитываются, естественно, только живые противники (СтатусПротивник = “жив”) и не сам стреляющий (Противник ¹ Стрелок).

Рис. 6.36. Вспомогательные функции программы «Дуэль»

Участник дуэли, придерживающийся второй (хитрой) тактики, перед выстрелом в цель или перед намеренным промахом должен пересчитать противников, стреляющих лучше его. Эту работу выполняет функция Меткие. В нее заложен такой же алгоритм перебора противников, как и в функции Самый_меткий. Функции Самый_меткий и Меткие в качестве аргументов имеют вектор Меткость, вектор Статус и скаляр Стрелок. Функции при своей работе вызывают логическую функцию And (логическое И ¾ см. пункт 1) с агрументом-вектором, которая возвращает 0 (логическое «нет»), если хотя бы один из элементов вектора (аргумента) равен нулю (см. главку «Mathcad и булевы (логические) функции» в этюде 3). Для реализации математической модели дуэли нам еще понадобится функция логического отрицания Not, определяемая также в пункте 1 на рис. 6.36.

Функция Победитель (пункт 3 на рис. 6.37) возвращает номер победителя в одиночной дуэли. При этом учитывается меткость и тактика каждого участника дуэли (два вектора-аргумента функции Победитель).

Рис. 3.37. Функция «Победитель»

Что происходит в функции Победитель?

В начале дуэли все участники живы: все три элемента вектора Статус принимают значение “жив” [50]. Далее проводится жеребьевка: определяется направление очередности выстрелов (если переменная Очередь равна единице, то очередность идет в таком направлении ...0®1®2®0®1®2.., если минус единице – ...0®2®1®0®2®1) и определяется первый стреляющий (переменная Стрелок). Кроме того, обнуляется переменная Убийство, по которой прерывается цикл выстрелов в дуэли.

Математическая модель дуэли опирается на цикл с выходом из середины (while ... break…): дуэль продолжается, пока не будут сделаны два результативных выстрела. В теле цикла while определяется Цель – самый меткий противник, которого убивают (СтатусЦель ¬ “убит”), если, во-первых, не промахиваются (МеткостьСтрелок > rnd(1)) и (And), во-вторых, не (Not) стреляют намеренно в воздух. Второе имеет место при хитрой тактике стреляющего (ТактикаСтрелок = 2) и (And), если метких противников более одного.

Определение следующего стреляющего ведется в цикле с постпроверкой (while ... break): цикл прерывается, когда, перебирая очередь, отмеченную выше (...0®1®2®0®1®2.. или ...0®2®1®0®2®1...), «натыкаются» на живого участника.

Возвращает функция Победитель номер участника дуэли (0, 1 или 2), оставшегося в одиночестве (значение переменной Стрелок по выходу из цикла).

Функция Победитель возвращает непредсказуемое целочисленное значение 0, 1 или 2, так как в ней в трех местах вызывается встроенная в Mathcad функция rnd, которая возвращает псевдослучайное число в интервале от нуля до значения аргумента функции rnd. Этот аргумент у нас равен либо единице (случайный выбор очередности выстрелов и имитация выстрела с вероятностью попадания, пропорциональной меткости стреляющего), либо трем (случайный выбор первого стреляющего – здесь дополнительно работает встроенная функция floor, возвращающая у положительного вещественного числа его «пол» (в смысле не «потолок» – по-английски a floor): floor(0.54), floor(1.82), floor(2.48) = 0...

Рис. 6.38. Проведение дуэлей

Функция Вероятность_победы (пункт 4 на рис. 6.38) возвращает вектор, элементы которого – это отношение числа побед каждого участника дуэли к общему количеству дуэлей (третий аргумент функции Верояность_победы; два первых аргумента-вектора – это параметры дуэлянтов: их меткость и тактика), то есть вероятность победы.

Теперь, когда все необходимые функции сформированы, можно проводить статистические испытания (см. пункт 5 на рис. 6.38) и фиксировать вероятности побед участников дуэли, исходя из их меткости и тактики. Если увеличивать число побед (переменная N), то, набравшись терпения[51], можно получить результат, близкий к теоретическому.

Задача о трехсторонней дуэли приводится во многих книгах[52]. И что интересно – она там решается неверно. Априори считается, что в этой дуэли самый слабый стрелок (Джон с номером 3) имеет наихудшие шансы выжить. Но если он немного подумает (хитрая техника), то вероятность выйти победителем у него становится самой высокой (52.2(2)%).

Наше решение (см. пункт 5 на рис. 6.38) говорит о том, что у Джона и так самые высокие шансы выжить (44-46%). Начиная хитрить, он мало чего выигрывает, но подводит Билла – своего товарища по несчастью стрелять хуже Сэма.

Откуда такая ошибка в постановке задачи? Дело в том, что у дуэлянтов есть еще одна, нулевая тактика. Если участники дуэли ничего не знают о стрелковых качествах соперников, то они бьют в первого попавшегося. Здесь вероятность побед можно подсчитать сразу без компьютера: Сэм – 43.48% (1/(1+0.8+0.5)), Билл – 34.78% (0.8/(1+0.8+0.5)) и Джон – 21.74% (0.5/(1+0.8+0.5)) или 100 - 43.48 - 34.78). Но мы составили программу и для этого случая (см. рис. 6.39).

Рис. 6.39. Проведение трехсторонней дуэли (бей в случайного)

Программа 6.39 не считает вероятность побед, а скорее проверяет качество генератора псевдослучайных чисел – добротность функции rnd (см. рис. 6.40).

Рис. 6.40. Статистические испытания функции rnd на трехсторонней дуэли

Задачу подправили, теперь ее можно развить.

Подсчитанная нами вероятность побед относится к ситуации, когда еще не проводилась жеребьевка по очередности выстрелов: переменная Очередь у нас либо единица, либо минус единица.

Но после жеребьевки шансы Сэма и Билла резко меняются. Дела Билла становятся совсем уж плохи (10-12%), если Джон после своего намеренного промаха передает право выстрела не ему (Очередь = -1), а Сэму (Очередь = 1). И наоборот: Сэм может потерять свои 30%, если после намеренного промаха Джона Билл будет стрелять в Сэма. У Джона вероятность победы (52.2(2)%) не зависит от очередности выстрелов.

Можно придумать и проанализировать четвертую тактику ведения дуэли: Билл и Джон сговариваются целить в Сэма, убить его, раз он такой меткий, а уж потом выяснять отношения между собой. Инициатором такого сговора, как понимает читатель, скорее всего, будет Билл. Джон пойдет на него, если не смоделирует дуэль на компьютере и не узнает, что из этого может получиться.

Еще одно задание читателю: доработать программы на рис. 6.36-6.40 так, чтобы они были пригодны для дуэли с любым числом участников.

Наше решение задачи о трехсторонней дуэли замыкает троицу новых решений старых проблем. Две другие – задача о рыбаках и рыбке (рис. 6.24 – там мы показали, что Дирак был не прав) и основная структурная теорема (главка «Remake», где мы показали, что альтернатива ¾ это не основная, а всего лишь вспомогательная структурная управляющая конструкция программирования).

Наша модель – не такая уж оторванная от жизни. Дуэли в чистом виде сейчас, к счастью, не проводятся. Но какое-то подобие дуэли со сговором участников наблюдается на рынках, включая финансовые. Кровь там не льется, но случаются инфаркты, лопаются компании, банки, разоряются люди и даже целые страны (Южная Корея, Индонезия, Малайзия, если иметь в виду 1998 год).

Теория игр, тактика поведения участников – это не только интересная, но и очень полезная штука. Недаром в 1998 году лауреатами Нобелевской премии по экономике стали ученые, применившие теорию игр к анализу работы биржи.

И все-таки сама модель чересчур искусственна. Что такое меткость дуэлянта и как ее определить? Проводить реальные статистические испытания? Но одно дело стрелять по мишеням, а другое – целить в живого человека. На дуэлях, как правило, не убивают наповал, а ранят с различной степенью тяжести. Подстреленный дуэлянт, если хватало сил и злости, стрелял в противника (дуэль Пушкина и Дантеса, например). Попытки «приземлить» задачу о дуэлях неизбежно потребуют привлечения аппарата теории нечетких множеств (ТНМ). В этюде 3 мы уже слегка коснулись ее положений.

Меткость дуэлянта – величина нечеткая, «размытая». Никто и нигде не измеряет ее числами, а только оценивает категориями (лингвистическими константами): «мазила», «хороший стрелок», «снайпер» и т.д. Статус дуэлянта – это никакая не булева переменная. Вспомним «консилиум врачей» (из этой компании запомнилась только фельдшерица Жаба) у лежащего без чувств Буратино: «Пациент скорее мертв, чем жив», – «Нет, пациент скорее жив, чем мертв» и т. д.

Оставим дуэли в покое (да и задача уж больно кровожадная[53]) и попытаемся решить что-нибудь попроще – нашу старую задачу об оптимальном пожарном ведре (см. этюд 2).

6.9.6. По-настоящему оптимальное пожарное ведро
(
English version of text)

Эта оптимизационная задача хорошо решается и численно (см. этюд 2), и аналитически (см. этюд 7). В ней под оптимизацией мы понимали максимизацию объема ведра при выбранной технологии его изготовления (вырезание сектора из круглой заготовки). Но при этом ведро теряло не только свою оптимальность, но и свое звание ведра: оно превращалось в пожарный тазик (его тоже нельзя поставить на пол и использовать не по назначению) или во вьетнамскую шляпу. Мы гнались за Числом (объем ведра) и потеряли Суть (функцию ведра – емкость для удобной переноски жидкости).

Тут автору вспоминается мультфильм о козленке, который научился считать и всех встречных-поперечных пересчитывал: «Я – это раз, петух – это два, свинья – это три и т.д.» У козленка из-за этого со всей пересчитанной живностью возникали крупные неприятности: «Ах! Ты меня сосчитал?! Ну, держись!» Но все кончилось хорошо. На то она и сказка.

В этой истории, как и в любой другой запоминающейся сказке, есть глубокий смысл. Стоит нам что-то пересчитать, как мы вступаем с этой пересчитанной субстанцией в глубокий конфликт. Природа не любит не только острых углов, но и счёта, который в ряде случаев просто убивает ее. Это можно наблюдать не только в биологии и физике, где инструменты познания часто неузнаваемо портят сам объект исследования, но и в computer science. И не только в области приложения компьютеров (счёта, грубо говоря) к решению естественнонаучных задач[54], но и в области применения компьютеров к самим компьютерам.

Врачу для установления диагноза незачем знать числовое значение температуры тела больного – 36.6, 38.9 и т.д. Достаточно выразить показания термометра диапазонами (категориями), о которых медики договорились заранее – «температура пониженная», «нормальная», «повышенная», «высокая», «очень высокая» («жар»)[55]. Границы этих оценок хоть и четко зафиксированы, но тем не менее размыты – «пушисты». Это определяется не только современными представлениями ТНМ, но и погрешностью самого термометра, методикой измерения температуры и др. Выпускник медицинского вуза не задумываясь скажет вам, где лежит граница между высокой и очень высокой температурой. Опытный же врач может этого и не знать, хотя диагнозы он выставляет не хуже начинающего доктора. Даже параметры больного, выраженные не в вещественном, а в булевом виде (реакция Вассермана, наличие палочки Коха, анализ на СПИД и т.д.), имеют «пушистые» границы. Об этом хорошо знают лаборанты, проводящие анализы. Если заглянуть в любой справочник терапевта, где описаны симптомы болезней, то, как правило, конкретных чисел (температура тела, артериальное давление, содержание гемоглобина в крови и т.д.) там не увидишь. Одни слова – повышено, понижено и т.д. Программы выставления диагноза по введенным в компьютер параметрам больного не получили широкого практического применения. Одна из трудностей в этом деле – перевод параметра (числа) в симптом (категорию).

Принято выделять три революции, переводившие программирование на новые уровни: структурное, обьектно-ориентированное и визуальное. Но эта революционность была больше обращена на программы (искусство ради искусства) и почти не касалась объекта программирования – тех моделей реального мира, свойства и события которого программно имитируются. Более того, ретроспективный взгляд может уловить и некую контрреволюционность в отказе, например, от аналоговых вычислительных машин и переход к цифровой технике. Хотя в последнее время здесь наблюдается какое-то подобие ренессанса – возрождение принципов аналогового моделирования на современных цифровых компьютерах (пример – среда MathConnex в составе Mathcad 7 и 8 Pro: см. приложение 7). Это можно отметить и в технологии визуального программирования, где воссоздаются прежние элементы управления (controls) – аналоги сумматоров, интеграторов и др. Но виртуальность этих неоаналоговых машин подразумевает и их строгую детерминированность (четкость), что влечет за собой не только положительные, но и отрицательные последствия. Сами же принципы ТНМ давно уже у программистов под рукой. В буквальном смысле. Мышка компьютера реагирует на два события – щелчок (click) и двойной щелчок (double click). А чем, собственно, один двойной щелчок отличается от двух одинарных? В длительности паузы между щелчками. Если ее выразить на языке человеческого общения (очень короткая, короткая, длинная и т.д.), то это будет типичным примером множеств с «пушистыми» границами. На сколько нужно увеличить короткую паузу, чтобы она превратилась в длинную и чтобы двойной щелчок распался на два одинарных? А сколько зернышек нужно добавить в горсть, чтобы она превратилась в кучу[56]?

В разгар структурной революции, когда во всех программистских «храмах» предавали анафеме ключевое слово GOTO[57], часто можно было услышать такую фразу: «Практически невозможно научить хорошо программировать студентов, ориентированных первоначально на BASIC: как потенциальные программисты они умственно оболванены без надежды на исцеление». Встречались и более категоричные предупреждения типа: «Осторожно! Занятие программированием может лишить вас будущего. Не думайте, что научившись программировать, вы чего-то добьетесь в жизни». Традиционное программирование как бы заставляет программиста смотреть на многоцветный мир сквозь черно-белые очки: булева переменная может принимать только два значения (да-нет), а вещественная – строго определенное в оговоренном диапазоне с фиксированной длиной мантиссы и т.д. Истина лежит посередине. Но и крайние точки зрения не бесполезны – они как бы подпирают истину с двух сторон, не давая ей скатиться к крайностям. Да и сами истины в чем-то «пушисты». А одна из них может звучать так: «Если хочешь познать мир (нечеткий, «пушистый», бесчисловой) и управлять им, то опасайся традиционных языков программирования и математических программ с их строгой детерминированностью».

Но вернемся к нашей задаче о пожарном ведре и попытаемся решить ее уже с привлечением аппарата ТНМ и с учетом мнения людей, которым – не дай Бог! – придется воспользоваться этим нехитрым средством пожаротушения.

Проведем своеобразный опрос общественного мнения и узнаем как можно больше о параметрах оптимального пожарного ведра: о его удобной[58] геометрии (радиусе основания конуса и высоте) и о его оптимальном объеме (о весе ведра с водой). Вот здесь-то и проявятся во всей своей красе положения ТНМ. Сколько нужно добавить в ведро воды, чтобы оно из легкого превратилось в тяжелое? На сколько нужно увеличить или уменьшить радиус или высоту ведра, чтобы оно перестало быть удобным? Вот эти сколько и являются типичными представителями нечетных множеств. В среде Mathcad, как и в других популярных пакетах, нет типов переменных для хранения таких величин. Но мы тем не менее мы постараемся решить поставленную задачу (рис. 6.41-6.45 – задача решена совместно с В.Усенко). Разберем ее по пунктам.

Рис. 6.41. Оптимальный радиус пожарного ведра

Пункт 1 (рис. 6.41). Матрица mr хранит представления людей об оптимальном (удобном) радиусе основания конуса пожарного ведра (r), выраженном в миллиметрах. Эти данные можно получить так: изготовить много ведер различной геометрии, дать людям поносить их и оценить по такой шкале:

· удобное (1);

· скорее удобное, чем неудобное (0.67);

· скорее неудобное, чем удобное (0.34);

· неудобное (0).

Можно принимать во внимание и другие оценки в диапазоне 0-1.

В пункте 1 мы ограничились семью точками, но их может быть намного больше: сколько людей, столько и мнений. Читатель при желании может опросить своих друзей и дополнить матрицу mr новыми столбцами.

Пункт 2. Данные опроса обрабатываются методом наименьших квадратов (см. этюд 4). На рис. 6.41 (как, кстати, и на рис. 6.42 и 6.43) в качестве аппроксимирующей кривой взята кривая нормального[59] распределения. Получена функция принадлежности по радиусу ведра mr, которая является одним из базовых понятий ТНМ: в привычной математике считается, что некая величина либо принадлежит, либо не принадлежит определенному множеству; в ТНМ допустимо говорить о том, что величина принадлежит множеству в некоторой степени (на столько-то процентов).

Пункт 3. Статистическую обработку принято заканчивать графиком.

Рис. 6.42. Оптимальная высота пожарного ведра

Пункты 4-6 (рис. 6.42) повторяют пункты 1-3, но уже для второго параметра ведра – его высоты.

Рис. 6.43. Оптимальный объем пожарного ведра

Пункты 7-9 повторяют пункты 1-3 и 1-6 для третьего важного параметра ведра – его объема (веса, массы). При этом предлагается дать такие оценки:

· ведро легкое (1);

· ведро скорее легкое, чем тяжелое (0.67);

· ведро скорее тяжелое, чем легкое (0.34):

· ведро тяжелое (0).

Данные опроса также обрабатываются с использованием нормального, но уже «однобокого» распределения (см. пункт 9 на рис. 6.43).

При проектировании технических систем, конечно, не проводят опрос общественного мнения, а прислушиваются к экспертам, к лицам, принимающим решения (ЛПР).

Рис. 6.44. «Перевернутое» оптимальное пожарное ведро

Пункт 10 на рис. 6.44. является ядром решения задачи: в нем генерируется двухпараметрическая функция принадлежности путем слияния (перемножения) ранее заданных функций принадлежности.

В ТНМ нет понятий сложения, вычитания, умножения и др., лежащих в основе традиционной математики и реализованных в среде Mathcad операторами «+», «-», «×» и т.д. В ТНМ умножение (пересечение множеств, And) заменено на операцию поиска минимума, а сложение (слияние множеств, Or) – на поиск максимума. Математика четких множеств является частным случаем математики нечетких множеств – в программах вместо функции (оператора) And можно использовать функцию поиска минимума, а вместо функции Or – функцию поиска максимума. В среде Mathcad, кстати, нет встроенных функций And и Or[60], но есть встроенные функции min и max – это мы уже отмечали в этюде 3. В нашей задаче функция принадлежности mrh получается путем нечеткого сложения (min) функций mr, mh и mv – нечеткое множество «удобное ведро» лежит на пересечении трех других нечетких множеств: «удобный радиус ведра», «удобная высота ведра» (пункт 6) и «нетяжелое ведро» (пункт 9).

Пункт 11. Вершина «горы» (поверхность функции mrh[61]) – это то место, где «лежит» самое удобное пожарное ведро.

Рис. 6.45. Проектирование оптимального пожарного ведра

Пункт 12 (рис. 6.45). Искать максимум функции mrh в среде Mathcad можно различными способами (см этюды 2 и 3). Мы поступим так: изготовим от 2 до 10 одинаковых ведер[62] из круглых заготовок различного радиуса R (от 10 до 500 мм с шагом 1 мм). Оптимальным (самым удобным) будем считать то ведро, у которого функция принадлежности mrh максимальна[63].

Даже не очень внимательный читатель заметит неточности, допущенные при решении задачи об удобном ведре. Вот три из них:

·ведро никогда не наполняется до краев;

·автор уж очень вольно обращается с такими понятиями, как объем, вес и масса ведра, путая их;

·не учтен вес пустого ведра, а также материал, из которого оно сделано.

Однако стоит еще раз мельком взглянуть на графики, иллюстрирующие нечеткие множества на рис. 6.41-6.43, чтобы понять важнейшую особенность решения задач с привлечением аппарата ТНМ. Наше решение вычленяет, если так можно выразиться, суть задачи, оставляя без внимания различные мелочи: плотность воды, вес пустого ведра, степень его наполнения и др.

Эта особенность в настоящее время реализована, например, в системах автоматического регулирования, где регуляторы, настроенные с учетом положений ТНМ, более «внимательны» к основному сигналу и менее восприимчивы к шуму. Оказалось, хотя это и кажется парадоксальным, что традиционные «четкие» алгоритмы управления качественно проигрывают «нечетким» либо являются их частными случаями. В теории автоматического регулирования наблюдался некий застой, так как никакие новые алгоритмы не могли сравниться со старым добрым пропорционально-интегрально-дифференциальным (ПИД) алгоритмом (законом) управления. Принципы ПИД-регулирования можно узреть в процедуре принятия решения о выдаче кредита клиенту банка, когда принимающий решение банкир учитывает, во-первых, количество денег на текущем счете просящего (пропорциональная составляющая – чем богаче клиент, тем больше денег ему можно дать в долг), во-вторых, динамику изменения текущего счета (дифференциальная составляющая – дела клиента на подъеме или в упадке) и, в-третьих, среднее количество денег у клиента за последние, к примеру, пять лет (интегральная составляющая – не занял ли клиент вчера денег на стороне, чтобы создать видимость своего благополучия). Можно учитывать и другие составляющие, но… три – красивое число.

ПИД-алгоритм регулирования как-то незаметно был фетишизирован. Идеи нечеткого управления – это свежая струя в теории автоматического регулирования, основные положения которой в настоящее время подвергаются ревизии. Правда, есть и другое мнение. Некоторые ученые полагают, что использование аппарата ТНМ в теории автоматического регулирования и в кибернетике вообще – это попытки замены одной неопределенности на другую (шило на мыло, грубо говоря). Только и всего. Наблюдающиеся эффекты повышения качества управления скептики объясняют тем, что на регуляторы лишний раз обратили внимание (принцип доброго слова, которое и кошке приятно). Кроме того, некоторые исследователи полагают, что ТНМ (ей всего лишь 30 лет, а открыл ее миру Л.А.Заде – американец иранского происхождения) – это хорошо забытое старое. Мы не случайно перешли к задаче об оптимальном ведре от задачи о трехсторонней дуэли. По традиции, четкие множества принято иллюстрировать кругами с резко оконтуренными границами. Нечеткие же множества – это круги, образованные отдельными точками: в центре круга точек много, а ближе к периферии их густота уменьшается до нуля; круг как бы растушевывается на краях[64]. Такие «нечеткие множества» можно увидеть... в тире ¾ на стене, куда вывешиваются мишени[65]. Следы от пуль образуют случайные множества, математика которых известна. Оказалось, что для оперирования нечеткими множествами годится уже давно разработанный аппарат случайных множеств...

Мы говорим нечеткое множество. А множество чего? Если быть последовательным, то приходится констатировать, что элементом нечеткого множества оказывается... новое нечеткое множество новых нечетких множеств и т.д. Вернемся к классическому примеру – к куче зерна. Элементом этого нечеткого множества будет миллион зерен, например. Но миллион зерен это никакой не четкий элемент, а новое нечеткое множество. Ведь считая зерна (вручную или автоматически), не мудрено и ошибиться – принять за миллион 999 997 зерен, например. Тут можно сказать, что элемент 999 997 имеет значение функции принадлежности к множеству «миллион», равное 0.999997. Кроме того, само зерно ¾ это опять же не элемент, а новое нечеткое множество: есть полноценное зерно, а есть два сросшихся зерна, недоразвитое зерно или просто шелуха. Считая зерна, человек должен какие-то отбраковывать, принимать два зерна за одно, а в другом случае одно зерно за два. Нечеткое множество не так-то просто запихнуть в цифровой компьютер с классическими языками: элементами массива (вектора) должны быть новые массивы массивов (вложенные вектора и матрицы, если говорить о Mathcad). Классическая математика четких множеств (теория чисел, арифметика и т.д.) – это крюк, с помощью которого человек разумный фиксирует (детерминирует) себя в скользком и нечетком окружающем мире. А крюк, как известно, ¾ инструмент довольно грубый, нередко портящий то, за что им цепляются. Термины, отображающие нечеткие множества (а их достаточно в этой и любой другой книге – «много», «слегка», «чуть-чуть» и т.д. и т.п.), трудно «запихнуть» в компьютер еще и потому, что они контекстно зависимы. Одно дело сказать «Дай мне немного семечек (зерна)» человеку, у которого стакан семечек, а другое дело – человеку, сидящему за рулем грузовика с семечками.

Можно ли усмотреть некий кризис в теории и практике программирования, связанный с противоречим между четкой структурой программ (данных) и нечетким миром? Следует ли разрабатывать «нечеткие» языки программирования для реализации «нечетких» алгоритмов и для размещения «нечетких» данных? Мнения здесь разные. Программисты (а за ними последнее слово) худо-бедно научились «запихивать» нечеткий мир в строго детерминированный компьютер. Пример на рис. 6.41-45.

6.10. A и B сидели на трубе

Сидели они не на простой трубе, а на пожарной, точнее – на пожарном ведре: сейчас будет рассказано об «общечеловеческом» смысле параметрических коэффициентов A и B (вернее Ar, Br, Ah, Bh, Av и Bv), входящих в аппроксимирующие выражения пунктов 2, 5 и 8 (рис. 6.41-43).

Давайте проведем глобальный статистический эксперимент – у всех взрослых людей на земле измерим какой-либо параметр: вес, рост, ум и т.д. ¾ словом все то, что можно измерить числом или оценить критерием (гений, талант, очень умный, просто умный... совсем дурак).

Полученные точки превратим в кривые (см. пункты 1-3 на рис. 6.41-43), где по оси X отложим параметр человека, а по оси Y – процент людей с данным параметром. При этом статобработку проведем отдельно для мужчин (м) и женщин (ж). Что мы получим?

Случай 1: Ам = Аж, но Вм > Вж:

Такие кривые получаются для тех параметров, значение которых у мужчин больше, чем у женщин (рост, вес, сила мышц и т.д.). Это связано с эволюцией – если мужская особь крупнее женской, то новые поколения укрупняются. У пауков, например, самцы намного меньше самок – пауки сейчас, слава Богу, более мелкие, чем в доисторические времена.

Случай 2: Ам < Аж, но Вм = Вж:

А так будут выглядеть кривые для параметров, значения которых у человека за последние несколько тысяч лет не менялись – ум, например. Многие вполне обоснованно полагают, что современный человек, если убрать налет образованности и культуры, ненамного умней древнего грека. Среди мужчин гениев[66] (нобелевских и прочих лауреатов, великих изобретателей, писателей[67] и художников – см. правый край графика) больше лишь потому, что и дураков среди мужчин достаточно (левый край графика). Но средняя женщина умнее среднего мужчины – центр «женской» кривой приподнят за счет меньшего разброса по краям: площади фигур под графиками одинаковы – никого не обижая, будем считать, что Господь Бог или Природа (кто как для себя считает) одинаково наделили умом обе половины человечества.

Теорию нечетких множеств, как уже было отмечено в этюде 3, можно попытаться приложить и к проблеме компьютерного пиратства. Закон делит всех людей на два четких множества: «множество легальных пользователей программ» и «множество нелегальных пользователей (пиратов)». В реальной жизни все намного сложней: нечетких множеств людей, причастных к компьютерам, великое множество (извините за тавтологию). Есть множество торгующих на «Горбушке» «черными» дисками (левый край оси – см. графики выше) и есть множество тех, кто принципиально работает только с легальными копиями и никогда не подаст руки согрешившим – нарушившим какое-либо лицензионное соглашение (правый край оси). Можно опять же над осью «грешник-праведник» построить горбатые статистические кривые, описывающие состояние компьютерного рынка в конкретной стране. Где находится максимум этой кривой, куда и с какой скоростью он перемещается во времени?

6.11. Открытое письмо пирата в адрес компьютерных изданий (English version of text)

Философско-религиозный аспект проблемы

Общекультурный аспект проблемы

Милицейский аспект проблемы

…Моральный аспект проблемы

Роман в письмах

Отзыв

Добавка от 2 марта 2006 г.

Открыв любой номер любого компьютерного издания, можно наткнуться на статью, касающуюся проблемы нелегального копирования и распространения программ. Данное письмо также затрагивает эту тему, но несколько в ином ключе. Здесь нет попытки кого-то осудить или оправдать. Автор просто пытается рассмотреть проблему в необычных аспектах: философском, религиозном, общекультурном, милицейском, моральном и даже... сексуальном.

6.11.1. Философско-религиозный аспект проблемы

Естествоиспытатель, желающий познать окружающий мир, не может прямо обратиться к Создателю – к Богу или к Природе, кто как для себя считает, а должен задавать вопросы самому объекту исследования, то есть должен проводить эксперимент – вносить в объект возмущения и фиксировать реакцию на них.

У программы есть авторы. Их имена далеко не всегда указаны на коробках, дисках и в документации, но они есть. Следовательно, какие-либо эксперименты над программами излишни. Возникающие вопросы нужно адресовать либо документации, либо самим авторам. Но! Если пользователю, к примеру, потребуется уточнить, в градусах или в радианах измеряется аргумент синуса, то он не будет рыться в документации, а просто напишет x:=sin(90) и посмотрит, чему окажется равна переменная x. Подобные эксперименты пользователи ставят ежечасно, обращаясь к документации только в особо сложных случаях и, как правило, не находя там ответа. Обращение же к Создателю проблематично. На hot-line сидят не авторы, а продавцы программ, что, как понимает читатель, далеко не одно и то же. Консультант фирмы скорее всего попросит вас перезвонить через пару дней, за которые он проведет свой эксперимент над программой и попытается найти ответ. Да и обращение к самому автору часто ничего не дает, так как он уже забыл свое детище и всецело поглощен новым проектом. Если даже это не так, то автор может и не помнить всех свойств, а уж тем более нюансов своего творения.

Из-за этого при работе с программами пользователь часто забывает, что это продукт ума и рук человеческих (Природа сотворенная), полагая (на уровне эмоций), что это плод работы анонимного и недоступного Создателя (Природа творящая), у которого нет hot-line. Здесь, по-видимому, и кроется философское объяснение (но ни в коем случае не оправдание) широкого распространения нелегального копирования программ. Имеются в виду не украинско-китайско-болгарские компакт-диски типа «Все для офиса» – воровство есть воровство[68]. Речь идет об относительно честных людях, ставящих на свой компьютер программу с того же лазерного диска, чтобы познать Природу и передать свои знания, например, студентам.

Можно считать, что Создатель, бросив сверху яблоко и угодив им по Ньютоновой голове, приоткрыл нам одну из тайн своего Божественного Замысла. Заслуга гения (Ньютона) – в умении оказаться в нужном месте в нужное время[69]. Программы (и не только гениальные) как бы тоже падают к нам сверху, и человек не обязан за них платить сумасшедшие по российским меркам деньги. Отсюда и живучесть идеи shareware, которой противятся в первую очередь продавцы, а не авторы программ.

Как говорится, есть мнение, что Бог создал по своему образу и подобию не только человека, но и компьютер. Написание для него программы – это вдыхание души в безжизненное нагромождение железок. Торговля телом (трансплантация органов, переливание крови или, наконец, проституция) – реалии наших дней. Покупка и продажа души встречается только в сказках и художественной литературе (история Фауста, например). Приобретая программный продукт, мы опять же покупаем только «тело» – диски, документацию, информацию и скидки по новым версиям, а главное – послепродажный сервис.

6.11.2. Общекультурный аспект проблемы

Откройте первую страницу любого западного издания и вы увидите предупреждение о том, что эту книгу (ее отдельные главы или страницы) запрещено копировать. Автор сначала написал «и вам бросится в глаза грозное предупреждение», но потом заменил на нейтральное «вы увидите». Все прекрасно понимают, что имеется в виду копирование в коммерческих целях. Как на Западе, так и у нас в библиотеках вполне легально стоят копировальные аппараты, на которых «ксерят» книги и журналы от корки до корки, исключая разве что ту самую страницу с грозным, а по сути пустым предупреждением. Снимать копии с печатной продукции любыми доступными способами (выпиской цитаты в тетрадку, например) можно в образовательных и научных целях. Более того, если кто-то препятствует такому способу распространения информации, то это расценивается как прямое нарушение прав автора. Не авторских прав[70], а именно «прав автора». За этой стилистикой скрывается то, что авторскими правами почти всегда распоряжается не автор, а издатель. Права же автора, это как права человека, которые «от Бога» и которые невозможно передать кому-либо. Появление на рынке «черных» копий книги расстраивает обладателя авторских прав. Автор же (обладатель прав автора) сначала радуется этому, а потом уж огорчается по поводу потери будущей и, как правило, эфемерной прибыли[71]. Размытость границы между коммерческим и некоммерческим использованием копий можно видеть и в другом. Аспирант «наксерил» чужих статей, слепил из них диссертацию (скажем мягче – часть диссертации), получил ученую степень, а через нее – высокооплачиваемое место на фирме или в университете. Даже если слово «слепил из них» заменить на «которые помогли ему написать», то суть дела не меняется: знания – это самый дорогой товар на цивилизованном рынке.

Такой подход к книжной продукции пользователи ЭВМ (а это сейчас самая читающая публика – в метро мелькает не только дамский роман, но и какой-нибудь User’s Guide или «Excel для «чайников») перенесли и на программные продукты (продукция, продукты – это все рыночные термины). Изучить программу так же интересно и полезно (в общекультурном, образовательном плане), как и книгу. Беда, а быть может, и счастье программ лишь в том, что копировать их намного проще, чем книги. Кроме того, даже самые гениальные программы, в отличие от классической литературы, умирают раньше срока завершения действия авторских прав. Пушкина или Шекспира сейчас кто угодно может издавать.

6.11.3. Милицейский аспект проблемы

В печати то и дело мелькают сообщения о том, что где-то на ВВЦ (бывшая ВДНХ), в Митино и у ДК им. Горбунова («Горбушка») ОМОН разогнал торговцев пиратскими CD-ROM с записями популярных программ для ЭВМ[72]. Первая реакция на это: «Наконец-то!» Но потом приходят другие мысли. Когда люди с автоматами наперевес проверяют документы у лоточников в подземном переходе, то девять прохожих из десяти думают не о том, что наводится порядок, а о том, что просто собирается дань. Десятый прохожий думает о том, что опять «заметут» всяких мелких сошек, а организаторы нелегальной торговли отделаются легким испугом. Боже упаси решать у нас какую-либо проблему чисто полицейскими мерами. До сих пор из этого ничего толкового не получалось, а если проблема и решалась, то выходил какой-то ГУЛАГ. Кроме того, здесь плавно выходит на первый план

6.11.4. …Моральный аспект проблемы

Милицейские рейды на рынки программ, и это отмечалось в печати, были проведены по наводке сотрудников российских компьютерных фирм, увидевших на лотках незаконные копии своих программных продуктов (см. фото – пиратскими дисками торгуют в 20 метрах от здания КГБ/ФСБ на Лубянке). Сотрудников, заметим, профессионально выросших на тех же пиратских копиях, правда, чужих программ. Нелегально ставили они их на свои компьютеры, конечно, в общеобразовательных и в научных целях, но... см. выше. К милицейским рейдам, говорят, приложило руку и московское отделение одной знаменитой компьютерной фирмы. Той самой, за которой тянется длинный шлейф судебных процессов по поводу нарушения чужих авторских прав. Знаменитой фирме можно посоветовать сначала разобраться с вопросами об авторских правах на оконный интерфейс, а потом уже «стучать куда следует». Вы видели главу этой фирмы? Похож он на человека, которого обокрали?

Библейское предание говорит о том, что Христос спас неверную жену от самосуда толпы, призвав первым бросить в несчастную женщину камень того, кто сам безгрешен. У автора такое чувство, что какое-то подобие самосуда над несчастными отечественными пользователями программ пытается совершить наша пресса (глас толпы)[73]. При этом на одну доску нередко ставятся и торговец с «Горбушки»[74], и вузовский преподаватель[75]. Да, и у того и у другого на руках нелегальные копии, но называть и, главное, судить их нужно по-разному, с учетом вышеизложенных аспектов. Торговцы с «Горбушки» вообще не имеют никакого касательства к закону об авторском праве. К ним нужно применять другие мерки и другие статьи закона – те, где говорится о нарушении правил торговли или даже о воровстве и разбое. Производители программных продуктов у нас в России (да и не только у нас) попали в какой-то заколдованный круг. С одной стороны, хочется защитить свои права всеми возможными средствами, а с другой – не имеешь на то морального права, ибо сам такие же, но чужие права неоднократно нарушал и будешь нарушать впредь – сын, например, дома скачивает с «черных» дисков игрушки.

Если программу воруют... Нет, камень бросать не будем и скажем по-другому. Если программу копируют без ведома автора или того, кому принадлежит copyright, то нужно не огорчаться, а радоваться. Автору, конечно, а не продавцу. Защищать же программу следует активными (хороший послепродажный сервис[76], электронный ключ, наконец), а не фискальными средствами. Аналогия из области адюльтера – пиратства на семейном фронте[77]. Если у вас красивая жена, то на нее засматриваются (и не только) окружающие. Бороться с изменами следует активными методами – подарки, признания, короче, хороший «послесвадебный сервис», пояс верности (электронный ключ), на худой конец[78]. Слежкой тут делу не поможешь. Тем более противно, когда осуждают чужих жен, да еще пытаются при этом писать какие-то «залесские»[79] декларации и статьи.

Автор, кажется, нашел для себя решение проблемы компьютерного пиратства. Считается, что нельзя быть немножко беременной. Но быть немножко честным[80] в коммерческом использовании чужих программ, наверно, можно. Автор со своими коллегами разрабатывает программы для электростанций (см. www.trie.ru, www.wsp.ru, www.vpu.ru и www.thermal.ru). Эта работа начиналась, естественно, с нелегального использования программ типа Turbo Pascal, Visual Basic и т.п. Но как только мы получили первые деньги за проданные программы, то пустили их не на зарплату, не на покупку нового компьютера, а на приобретение использованных инструментальных средств – даже тех, с которыми мы уже не работали[81]. Теперь у нас все коммерческие проекты базируются на легальных программах, образовательные же (автор работает в Московском энергетическом институте) – пока нет. Вернее, немножко нет: покупается (да и то не всегда – пусть в нас бросят камень) программа для одного компьютера, а устанавливается на все машины в учебном классе[82]. Но решение этой проблемы – дело времени. Россия либо окончательно увязнет в разного рода кризисах, либо наладит нормальную систему образования (здравоохранения, социального обеспечения и т. д.) с нормальным финансированием. Третьего не дано. А пока же неплохо установить мораторий не на использование нелегальных копий, а на осуждение тех, кто это делает в общеобразовательных и учебных целях, понимая при этом, что диапазон коммерческого использования чужих программ очень широк. На одном его конце аспирант, обрабатывающий экспериментальные данные на компьютере, а на другом организатор доставки и распространения «черных» лазерных дисков. Хотя это не самый страшный «черный» бизнес: радуйтесь, что торгуют «железом» и программами, а не настоящими винчестерами и наркотиками.

Чехов, по его собственному признанию, по каплям выдавливал из себя раба. Но ему даже в голову не приходила мысль попытаться насильно выдавить что-то гадкое из читателей. Чехов своими произведениями помогал им становиться лучше, только и всего. Давайте же выдавливать из себя по каплям (вычерпывать ведрами) компьютерного пирата. Делать это надо без истерик, без милицейских шмонов и тем более без стукачества, оставаясь наедине со своею совестью, поглядывая в свой кошелек и в Уголовный кодекс.

Автор боится, что проблема компьютерного пиратства у нас в стране решится чисто по-советски – через дальнейшее увеличение административного аппарата. Будет, например, создана компьютерная полиция, которая по примеру своих собратьев из налоговой полиции не сможет сунуть нос в миллиардные особняки, как грибы растущие в Подмосковье без всяких налоговых деклараций, или на оптовые рынки, отоваривающие пол-Москвы без каких-либо кассовых аппаратов. Попортить нервы предпринимателю-производственнику, еле-еле выживающему в нашем налоговом беспределе – это полиция может. Налоговая полиция должна вышибать двери не только у нелегальных бутлеггеров, но и в шикарных кабинетах начальства, отделанных на бюджетные средства. В первом случае нужно надевать бронежилет, а во втором – памперсы. Так вот, автор боится, что компьютерная полиция, если она будет создана, первым делом пойдет не на «Горбушку», а в какой-нибудь ВУЗ или НИИ, чтобы наложить штраф на вышеописанного аспиранта. (Вставка от 14 ноября 2006 г. – такой «шмон» недавно состоялся в Волжском филиале МЭИ. Вставка от 13 января 2007 г. см. http://www.lenta.ru/news/2007/01/12/ponosov/).

Старый российский вопрос «Что делать!?» (вставка 18/11/2006)

  1. Необходим second hand и при работе с программами. Почему я могу продать на сторону свой старый компьютер, но не могу продать старые программы, установленные на нем. Чем, собственно, одно ware (software – «мягкий» продукт производства») отличается от другого – от hardware.
  2. Почему бы софтверным фирмам и их дилерам не торговать устаревшими версиями программ. Мне, например, не нужна самая свежая и самая дорогая версия программы. Мне достаточно «старого коня, который борозды не испортит». Но нет! Как только появляется новая версия программ старые версии (копии) из продажи тут же изымаются. Хорошо бы тут показать, как эти нераспроданные версии уничтожаются, например, гусеницами тракторов вместе с контрафактными дисками. На устаревшие программы хорошо бы наклеивать бирку «Специальное предложение» и продавать по сниженным ценам, как сейчас продаются в магазинах скоропортящиеся или вышедшие из моды товары.
  3. Можно и нужно речь вести о так называемой «Программной амнистии». Наезды на вузы, например, пока прекратить, а дать им возможность постепенно войти в законное русло использования программ на своих компьютерах.
  4. Можно говорить и о реструктуризации долгов бюджетных организаций софтверным фирмам, чьи программы используются без соответствующих лицензионных соглашений. Такие соглашения нужно заключать сейчас, а оплату программ растягивать во времени. Так, например, поступают сейчас со странами, попавшими по разным причинам в долговую зависимость от групп международных кредиторов.
  5. На компьютеры, установленные в учебных и других бюджетных заведениях, можно заводить некий паспорт, где будет отмечено, какие программы по какой схеме тут используются (лицензионные и оплаченные, лицензионные, но еще не оплаченные, подаренные, second hand и т.д.)

Жду новых предложений!

Часть полученного за книгу гонорара автор тратит на приобретение легальной версии текстового редактора, с помощью которого эта книга писалась. Но автор хочет быть с читателем откровенен до конца и сообщает, что программа будет куплена:

·если на это хватит гонорара;

·если не появится новая версия текстового редактора – покупать (или «воровать») придется уже ее;

·если автор не передумает.

Другую часть полученного за книгу гонорара автор потратит на приз читателю, приславшему самую короткую программу перевода римского числа в арабское. Для «затравки» автор помещает в конце этюда программу перевода арабского числа в римское (см. первую половину рис 6.46).

Рис. 6.46. Перевод чисел из арабской в римскую систему и наоборот

Так было написано во втором издании книги про Mathcad 7. После выхода книги в свет автор получил решение от Артема Михайлюка, студента Киевского политеха (см. вторую половину рис 6.46). Он же прислал и совсем короткое решение – см. первую половину рис 6.47.

Рис. 6.47. Работа банкомата

Роман в письмах

Добрый день, господин Очков! (к сожалению, не знаю Вашего имени и отчества)
Обращается к Вам
N из г.NN.
Фирма "
NNN", в которой я работаю, выпускает газету "NNNN". Эта газета юридической и экономической тематики. Каждый выпуск мы посвящаем определенной проблеме, и в октябре это – "Пиратские копии программных продуктов". При поиске в Интернете определенного материала я нашла Вашу статью "Открытое письмо пирата в адрес компьютерных изданий".
Она показалось мне достаточно интересной с точки зрения всего того материала, который мы хотим публиковать. Думаю, что читателям будет интересно узнать разные мнения на вышеназванную проблему.
В связи с этим, просим у Вас разрешение на публикацию Вашей статьи.
И будем рады любым Вашим предложениям.

 

Уважаемая N (к сожалению, не знаю Вашего отчества)!
Спасибо за интерес к моей статье, вернее, к главе из книги "Mathcad для студентов и инженеров" см. http://twt.mpei.ac.ru/ochkov/mc8Pro.book/index.htm
Я не возражаю против публикации. Прошу только:
1) Показать мне статью, если Вы ее в чем-то измените или дополните. Если к статье будет комментарий, то неплохо и его предварительно увидеть.
2) Решить вопрос с гонораром
3) Переслать мне газету со статьей, когда она выйдет.
С уважением,
Очков Валерий Федорович

 

Добрый день, Валерий Федорович!
Изменять и дополнять Вашу статью мы не будем.
А вот вопрос с гонораром достаточно трудный. Наша газета не является прибыльной: тираж ее только 2 500 экземпляров и распространяется она бесплатно. Но мы можем предложить Вам разрекламировать Вашу книгу (естественно, с указанием интернетовского адреса). Сразу оговорюсь, что наша аудитория – это руководители, бухгалтеры и юристы практически всех фирм нашего небольшого города. Газета несет чисто деловой характер, соответственно, если у Вас есть интерес привлечь данную публику, то мы с легкостью можем это сделать. Если данное предложение Вас не устраивает, то присылайте свое.
P.S. Думаю, ко мне можно обращаться и без отчества (мой возраст пока это позволяет:))
С уважением,
N.

 

Уважаемая N!
Гонорар авторам выплачивается не из прибыли, а из тех же источников, из которых оплачивается бумага, типографские услуги и пр.
Пиратство (тема Вашего обзора) – это когда не оплачивают интеллектуальный труд: труд бумажников и печатников не оплатить нельзя, а труд автора – можно.
Бог с Вами, публикуйте мою статью! Хорошо бы ее дополнить нашей перепиской.
В.Очков

 

Добрый день, Валерий Федорович!
Думаю, что если касаться экономической стороны данного вопроса, то Вы правы полностью. Без гонорара ни один человек работать не будет (законы рынка, что поделать). Так что, благотворительность в этом деле ни к чему – публиковать Вашу статью мы не будем (это уже этичная сторона вопроса).
Успехов и удачи в Вашем нелегком авторском труде!
С уважением,
N.

 

Уважаемая N!
Ваш политика с выпуском газеты – это типичный пример пиратства.

Компьютерное пиратство – это когда есть деньги на "железо", но нет денег на "софт".

Музыкальное пиратство – это когда есть деньги на трансляцию песен, но нет денег на гонорары композиторам.

Издательское пиратство (наш случай) – это когда есть деньги на бумагу и типографию, но нет денег на гонорары авторам и т.д.

Не спрашивая Вашего позволения (а чего церемониться с пиратами!) я дополню мою статью нашей перепиской, убрав, естественно, имена.

В.Очков

 

А вот как звучала тема интеллектуального пиратства в конце XVIII века:

«Книгопродавцы изо всей Германии съезжаются в Лейпциг на ярманки <…> и меняются между собой новыми книгами. Бесчестными почитаются из них те, которые перепечатывают в своих типографиях чужие книги и делают через то подрыв тем, которые купили манускрипты у авторов. Германия, где книжная торговля есть едва ли не самая важнейшая, имеет нужду в особливом и строгом для сего законе.» (Н.М.Карамзин. «Письма русского путешественника»)

Отзыв 2

Уважаемый Автор,

 

благодарю Вас за публикацию (в интернете) "Открытого письма" - целиком разделяю и поддерживаю Вашу точку зрения <>.

 

Позвольте мне от себя маленький комментарий на ссылку [3]: в английском языке понятие Copyright  относится именно к правам на рукопись (исходный текст), что явствует из первого, основного значения слова copy (а также третьего значения - цитируется по словарю Lingvo 6.0, который приобретен мной через магазин OZON):

copy    1. сущ. 

1)  а) экземпляр; список (с рукописи)  advance copy 

б) рукопись  ­ fair copy  ­ clean copy  ­ rough copy  ­ copy holder 

в) образец 

г) вариант 

 

2)  а) копия   Syn:  duplicate, facsimile, model, replica, reproduction, transcript  Ant:  prototype 

б) копия (любого произведения искусства, также авторская); репродукция  Syn:  duplicate, replica, reproduction, cast 

 

3)  а) материал для статьи, заметки, книги, публикации 

б) рукопись для сдачи в печать (отсюда copyright) 

в) текст рекламного ролика, объявления 

... и т.д.

 

Еще одно замечание, уже из опыта личного общения с представителями зарубежных компаний, распространяющих научную литературу (академические журналы, полнотекстовые базы данных для библиотек и т.п.): сейчас в США существенно ужесточились условия использования ксероксов в библиотеках - ряд судебных дел, возбужденных по искам всемирно известных научных издательств вынуждают библиотекарей либо совсем отказываться от подобной услуге для своих читателей (платной или безвозмездной - все равно), либо отдавать этот "печатный станок" на откуп сторонним Ltd., чтобы не навредить своей репутации.

Конечно, сами авторы от этого никак не выигрывают, но... таковы законы бизнеса.

 

С наилучшими пожеланиями


Кирилл Ладыгин, руководитель проекта

Балтийский Исследовательский Центр 192019, Россия, Санкт-Петербург, наб. Обводного канала, 24а, оф. 84.
Тел. (812) 325 2026 Факс (812) 103 5399 http://www.brcinfo.ru kl@brcinfo.ru

 Добавка от 2 марта 2006 г.

Компьютерное пиратство и работорговля

Одно из препятствий на пути вступления России в ВТО – это проблема компьютерного пиратства. Нас упрекают за слабые усилия государства в защите интеллектуальной собственности вообще и за недостаточную борьбу с контрафактными компьютерными программами, в частности.

Мы же, с одной стороны, регулярно показываем по TV рейды правоохранительных органов по компьютерным рынкам и гусеницы бульдозеров, давящих «черные» диски, а с другой – спокойно наблюдаем развалы программ у лотошников на Мясницкой улице Москвы под самым носом у главного нашего правоохранителя – у ФСБ. Кроме того, у нас почти на официальном уровне бытует мнение, что в развивающейся стране (а мы сейчас такой и являемся), но имеющей высокой научно-технический потенциал, в стране, где уборщица в банке получает в несколько раз больше профессора в университете, компьютерное пиратство – вещь, конечно, очень нехорошая, но не только неизбежная и даже полезная…

Тут на ум приходят аналогии двухсотлетней давности.

Больше всех «давят» на Россию в вопросе компьютерного пиратства, естественно, США. Один из инструментов этого давления – пропуск в ВТО. Но…

В первой половине девятнадцатого века на США (и, кстати, на Россию) «давила» Европа по вопросу… рабства и работорговли. Америка же отвечала Старому Свету «почти на официальном уровне» в том плане, что в условиях «развивающейся страны» рабство неизбежно. Американцы могли в те времена приглашать людей из Европы в Америку, но не имели денег на людей с Черного Континента. Из-за этого они (американцы Юга) шли на не вполне законные, а, проще говоря, криминальные меры – отлавливали негров в Африке и переправляли их в кандалах в Америку. Теперь же американцы могут осуждать рабство и выплачивать потомкам рабов огромные компенсации. Но многие при этом и сейчас «полуофициально» признают, что без рабства Америка вполне вероятно и не стала бы через сто лет ведущей мировой державой. Но, «что было, то было» – в истории, говорят, нет сослагательного наклонения…

Вернемся в наше время и в Россию. Сейчас мы имеем возможность и обязаны покупать компьютерное оборудование (hardware – «железо»), но уже на программы (софт) денег нет… Тем более, его можно «отловить» в Сети и «в кандалах переправить» на свой компьютер. Иначе нам не подняться… И пусть нас в этом упрекает кто угодно, но не американцы. Потом мы тоже осудим это явление и  вполне вероятно выплатим компенсации…

Но сравнение, конечно, не вполне обоснованное. В первом случае калечились судьбы людей – вспомним «Хижину дяди Тома, а во втором некие миллиардеры недополучают миллионы. Вы видели их!? Похожи они на людей, которых обворовали…

Операции по переводу чисел мы проводим каждый день по многу раз, расплачиваясь за покупки. Алгоритм перевода чисел может быть применен, например, в работе банкомата (см. вторую половину рис 6.47).

6.12. Отладка Mathcad-программ

Каждый, кто когда-либо серьезно занимался программированием, знает, что написать программу можно за несколько минут. Но на поиск ошибки в ней могут уйти часы, дни, недели...

Английский эквивалент термина отладкаa debugging заслуживает отдельного разговора. A bug по-английски – жучок, а приставка de означает удаление. Сам термин debug дословно можно перевести как обезжучивание. Эта калька с английского не такая уж бессмысленная. Один из первых компьютеров стал барахлить из-за того, что в его электронных внутренностях запутался таракан, закоротил контакты, обуглился и, как некий связист-камикадзе, замкнул их, внеся тем самым изменения в электронную схему машины.

К сожалению, пакет Mathcad не оборудован штатными средствами отладки. А к ним обычно относят следующую тройку инструментов:

1. Трассировка программы (Trace), когда после ее запуска цветом или жирным выделением отмечаются выполняющиеся операторы. Так можно проверить соответствие порядка выполнения операторов задуманному алгоритму. Программу можно выполнять и пошагово – очередной оператор выполняется после нажатия программистом какой-либо оговоренной клавиши. При этом можно «заходить» или не «заходить» в функции или процедуры. Не заходят в них в тех случаях, когда они отлажены и оттестированы отдельно (заранее).

Система Mathcad, выполняя операторы документа, своеобразно трассирует их. Если какой-либо оператор выполняется достаточно долго (суммируются элементы объемного вектора, например), то он оконтуривается и штрихуется зеленым цветом. Это можно было бы назвать трассировкой, если такое выделение операторов велось бы и в теле программ с циклами и альтернативами. Но система Mathcad рассматривает программу как единый оператор (второй атрибут программирования) и не подсвечивает операторы в нем, а оконтуривает и подсвечивает всю программу: «Ждите ответа!»

2. Пошаговое выполнение операторов обычно сопровождают просмотром (Watch) текущих значений всех или некоторых переменных. При этом на дисплей выводится специальное окно, где отмечаются имена переменных, их тип, текущее значение и др.

3. Критические операторы (места) программы отмечают точками останова (BreakPoint), где компилятор прекращает выполнение машинного кода. После этого программист может просмотреть значения всех или некоторых переменных (см. выше), подправить программу и дать команду на ее дальнейшее выполнение (выполнять программу далее в нормальном режиме, пошагово или даже пустить вспять, если чувствуется, что ошибка случилась ранее отмеченного места).

Но повторяем, среда программирования Mathcad лишена каких-либо специализированных средств отладки. Объяснить и в какой-то мере оправдать это можно лишь тем, что программирование – это лишь вспомогательный инструмент при решении задач[83]. Но при отладке самой программы Mathcad, по-видимому, инструменты отладки использовались. Автор об этом узнал случайно, когда работал с самой первой бета-версией Mathcad 8, нажав правую кнопку мыши с курсором, помещенным на рабочем листе. Вот что появилось на экране дисплея (рис. 6.48): локальное меню с волшебным словом «Debugger»:

Рис. 6.48. Окно отладки Mathcad-документа в бета-версии Mathcad 8 Pro

Можно предположить, что если курсор помещался в рамках программного блока, то выводился список локальных переменных программы и выполнялись другие отладочные операции. Но эта таблица была «мертва», а в последующих бета- и в коммерческой версиях Mathcad 8 ее совсем не стало[84].

Тем не менее потребность в отладке программ осталась, и мы о ней поговорим.

Существует две категории ошибок в программах. Ошибки первой категории связаны с неправильным обращением к функциям и операторам Mathcad, формирующим программу. Вот типичное сообщение дефектной программы: «Индексы переменной-вектора (матрицы) вне оговоренных пределов!» Вторая категория ошибок связана с дефектом самого задуманного алгоритма: программа работает без аварийных остановов, но выдает совсем не то, что от нее ожидалось.

Так или иначе, программу нужно «обезжучивать» – искать и удалять ошибки в ней. Вот семь советов на этот случай:

1. Прежде чем писать Mathcad-программу стоит «прощупать» ее основные операторы и порядок их выполнения в «беспрограммном» режиме. Мы так уже поступали, решая задачу о рыбаках и рыбке (рис. 6.22-6.24), например. А вот более «серьезный» пример. На рис. 6.49-6.50[85] показано, как в среде Mathcad определяется коэффициент полезного действия (кпд) цикла Ренкина, где из котла в турбину поступает перегретый (острый) пар; отработавший (мятый) пар сбрасывается в конденсатор, из конденсатора вода насосом закачивается обратно в котел: так замыкается простейший цикл работы воды и водяного пара. Необходимо определить кпд этого цикла (отношение полезной работы турбины к затраченному теплу) в зависимости от его параметров: от температуры и давления острого пара и давления в конденсаторе (пункт 2 на рис. 6.49). Для расчета нам потребуются термодинамические функции воды и водяного пара: в пункте 3 делается ссылка (команда Reference… в меню Insert) на Mathcad-документ, их хранящий. Сама методика формирования этих функций (одно- и двухмерная сплайн-интерполяция) описана в этюде 4. После такой ссылки кпд цикла рассчитывается по несложным формулам, вытекающим из закона сохранения энергии.

Рис. 6.49. Расчет кпд цикла Ренкина (ручной режим – начало)

Если теперь поменять параметры цикла (пункт 2 на рис. 6.49), то измениться и кпд[86] (конец пункта 3).

Рис. 6.50. Расчет кпд цикла Ренкина (ручной режим – продолжение)

Этот расчет (отлаженный и протестированный – в Mathcad-документе на рис. 6.49-6.50 выведены для контроля значения всех переменных, задействованных в расчете) целесообразно сгруппировать в функцию-программу (пункт 4.1 на рис. 6.51), по которой очень просто получить расчетные таблицы (пункт 4.3 на рис. 6.52) или графики (пункт 4.3).

Рис. 6.51. Расчет кпд цикла Ренкина (функция пользователя)

При формировании функции следует не писать операторы заново, а копировать их из отлаженного документа, дабы не наделать новых ошибок.

Рис. 6.52. Расчет кпд цикла Ренкина (работа функции пользователя)

Эту функцию можно использовать в новых расчетах, например, при определении реального, а не теоретического кпд реальной тепловой электростанции[87].

Если в программе есть цикл (не термодинамический, а цикл выполнения блока операторов), то его можно развернуть: дублировать операторы блока или вести расчет по этому блоку столько раз, сколько нужно. Так мы поступали, «беспрограммно» решая задачу о рыбаках и рыбке (рис. 6.22) и краевую задачу об эпидемии (рис. 5.1-5.4). Кроме того, не следует забывать о встроенных в Mathcad-функцях if и until, реализующих основные структурные конструкции (выбор и повторение) вне программ. На рис. 6.1 с помощью этих функций «запрограммирован» сложный алгоритм – поиск корня алгебраического уравнения методом половинного деления.

2. Да, в среде Mathcad специализированных средств отладки программ нет. Но они есть в других популярных программных средах: Visual Basic, Visual C, Delphi: и др. Задуманный алгоритм можно сначала реализовать и опробовать в «настоящих» программных средах, а потом уж переписать для Mathcad. Так мы поступали, решая задачу о рыбаках и рыбке (рис. 6.23 и 6.24) или составляя программы поиска корня алгебраических уравнений методом половинного деления и методом Ньютона, а также при поиске минимума методом золотого сечения. Автор задачу о трехсторонней дуэли (рис. 6.36-6.40) сначала поставил, а, главное, отладил в среде языка Visual Basic, а уже потом переписал для Mathcad, где это сразу сделать не удалось.

Воспользоваться этим советом можно лишь в том случае, если в программе нет специфических Mathcad-операторов и функций, отсутствующих в «настоящих» языках.

3. Создавая программу-функцию, на первом этапе стоит сделать так, чтобы она возвращала не только значение «одноименной» переменной, но и некоторых других, задействованных в расчете. Для этого достаточно в конец программы поставить не имя главной переменной, а какой-либо локальной, вспомогательной. Можно все переменные, задействованные в расчете, объединить в вектор и выдать их все на дисплей.

В Mathcad-программу можно вставлять своеобразные точки останова (BreakPoint): операторы return X, где X – это какая-либо локальная переменная программы. После отладки эти операторы убираются совсем или нейтрализуются таким оператором: return X if 2<1.

Если программа зацикливается и ее приходится прерывать нажатием клавиши Esc (текущие значения локальных переменных при этом просмотреть, увы, невозможно), то можно посоветовать в подозрительный цикл вставить дополнительный счетчик. Расчет будет безаварийно завершен, когда значение счетчика достигнет заданной программистом величины.

4. Если функция имеет ограниченный набор значений аргументов и/или возвращает ограниченный набор значений, то стоит не полениться и протестировать функцию глобально. Так, на рис. 3.14 в этюде 3 одноместные, двуместные и трехместные логические функции при тестировании возвращают все, что от них требовалось: у функции Not(x) два значения, у функций And(x1, x2) … AntiOr(x1, x2) – четыре значения, а у функции Решение(х1, х2, х3) – восемь.

5. Случай, описанный в пункте 4, довольно редкий. Если аргументы функции имеют действительные значения[88] и (или) она возвращает действительные числа, то стоит проверить работу новоиспеченной функции в «экстремальных условиях» – на границах допустимых значений.

6. Вот хорошее правило: после создания программы ей нужно «подсунуть» условия задачи, решение по которым заранее известно. Так, на рис. 6.17-6.20 Mathcad-программы возвращают корни алгебраического уравнения, используя различные способы (метод половинного деления, метод Ньютона, метод секущих). Анализируемое уравнение у нас было простое: х2 - 3 = 0, корни которого известны заранее: плюс-минус квадратный корень из трех. На рис. 6.5 показаны программы решения обыкновенных дифференциальных уравнений и систем методом Рунге ¾ Кутты. Прежде чем с помощью этих функций заняться решением задачи о развитии эпидемии, мы «потренировались» на «кошечках»: рассчитали с их помощью значение основания натурального логарифма (число е).

7. Решая поставленную задачу, нужно постараться разбить ее на отдельные блоки и оформить их в виде отдельных коротких программ[89]. Это позволит локализовать ошибку и облегчить ее поиск. Объемная Mathcad-программа, в которую вкралась ошибка (ошибка алгоритма или ошибка в использовании инструментов Mathcad) – это что-то неисправимое ¾ «вещь в себе». Так, решая задачу о трехсторонней дуэли (рис. 6.36-6.40), мы выделили в отдельные функции такие действия стреляющего, как определение самого меткого противника и пересчет противников, стреляющих лучше[90]. Эти функции были протестированы и только потом стали вызываться из основной программы.

Разбивать на отдельные блоки программу целесообразно не только для оформления в функции, но и просто для отладки, для конструирования. Mathcad в этом отношении обладает уникальными возможностями: отдельные блоки программы (тело цикла, плечи альтернатив) из программы можно изъять и расположить вокруг. На рис. 6.53 изображена «разъятая» программа поиска минимума методом золотого сечения (ее рабочий вариант см. на рис.6.26). В самой же программе остались «местодержатели» (placeholder).

Рис. 6.53. Разъятая Mathcad-программа

Программы можно не только «обезжучивать» (отлаживать), но и «нажучивать». В стародавние времена, когда программы в ЭВМ вводили не их авторы, а девочки-перфораторщицы и готовые тексты программ из-за этого содержали много «глупых» ошибок типа 5 вместо S, 1 (один) вместо I («и» латинское) и т.д., практиковался (больше, конечно, в теории, а не на практике) довольно оригинальный способ отладки по принципу «клин клином вышибают». Если нужно было узнать, сколько в программе осталось «жучков», то в нее... вводили еще сотню ошибок. Затем другой человек эту программу отлаживал. И если оказывалось, что он, к примеру, выловил 50 специально введенных ошибок и 10 первоначальных, то с определенной долей вероятности можно было считать, что в программе осталось еще с десяток «натуральных» жучков-ошибок. Кстати, подбор искусственных ошибок – это и наука, и искусство высокого класса, а сам процесс отладки очень трудоемкий, способный довести программиста до белой горячки. Недаром по-английски to go bugs означает сойти с ума. Очень часто бывает проще стереть написанную программу и ввести ее заново, чем искать в ней ошибки. Один коллега автора долго не мог понять, что происходит в такой коротенькой цепочке операторов:

a := 3                     b := 1              a - b= -3

Если от трех отнять единицу, то должна выйти двойка, но никак не тройка, да еще с минусом? Ответ оказался прост, но эта простота была уж точно «хуже воровства». Дело в том, что в приведенном примере не b вычитается из a, а переменная a умножается на минус b. В среде Mathcad начиная с 7 версии, если константа умножается на переменную, то знак умножения можно опускать. Этот прием особо удобен при вводе размерностей 5 m, 3 kg и т.д. – человек еще до общения с компьютером привык не ставить тут знака умножения. В вышеприведенном примере сначала было записано 3 b=, но потом тройку заменили на переменную a, а b на минус b. Услуга Mathcad (программисту не нужно вводить знак умножения) здесь оказалась «медвежьей». Вот еще иллюстрации принципа «Не верь глазам своим!»:

·        MT – что это? Транспонированная матрица M или матрица (вектор, скаляр) M в степени T?

·        Аi ¾ это i-й элемент вектора А или i – это часть имени переменной с текстовым индексом (набираем A.i, получаем А i)?

·        В переменной Стрелок первая буква английская «си» или русская «эс»?

Свести с ума может и такая «первоапрельская» шутка. Программист на минутку отлучился от компьютера, а «шутник» вверху Mathcad-документа, на правом, невидимом листе написал sin(x):=cos(x), e:=p или что другое из области «crazy[91]». Можно у отдельной переменной незаметно поменять шрифт с Variable на User1, например – эффект тоже будет очень интересным. В таких ситуациях не стоит пытаться отыскать ошибку – лучше начать все с «чистого листа»: создать новый пустой рабочий документ и в него постепенно переносить отдельные фрагменты «сумасшедшего» Mathcad-документа, отлавливая ошибку…

6.13. Оптимизация Mathcad-программ

Программист, написав и отладив программу, как правило, на этом не успокаивается и начинает ее улучшать – оптимизировать. Таким программистам можно посоветовать повесить на стене перед глазами такой листочек:

«За все нужно платить!»
 «Лучшее ¾ враг хорошего!»
«Не до жиру, быть бы живу!»

Далее в тексте читатель будет встречать подобные тривиальные истины, некоторые из них он может также вывешивать в виде плаката[92].

Поговорим о том, что можно улучшить в программах – хотя бы в тех, которые помещены в этой книге.

Программы можно оптимизировать по разным параметрам. Вот три основополагающих:

·        Время выполнения программы;

·        Объем программы: место, занимаемое ею в ОЗУ компьютера, длина файла с исходным текстом программы, хранимого в архивной памяти.

·        Читабельность программы; степень ее открытости для изучения другими людьми и для доработки самим автором или кем-то другим.

Последнее качество в отличие от двух первых не так просто выразить числом, на которое можно целенаправленно влиять. Но мы уже рассмотрели понятие удобное пожарное ведро и знаем, как нечеткие величины можно обрабатывать четкими методами (см. рис. 6.41-6.45). Открытость программ очень важна в среде Mathcad, так как этот пакет интенсивно используется в сфере образования. Все три параметра (и еще какие-то другие) можно объединить в один интегральный и применить к нему метод экспертных оценок с функциями принадлежности какого-либо элемента (параметра) нечеткому множеству «оптимально-неоптимально».

Все три вышеотмеченные качества взаимосвязаны. Только в очень неряшливо написанной программе все параметры можно улучшить. Обычно же бывает так, что, улучшая читабельность программы человеком, мы ухудшаем ее «читабельность» компьютером: комментарии в программе (в нашем случае – текстовые константы) не только увеличивают объем программы, но и замедляют ее прогонку.

Вот другой пример. Если в программе на рис. 4.10 (сплайн-интерполяция) исходные векторы и матрицы термодинамических параметров водяного пара переместить в файл на диске, а в программе оставить операторы его считывания (функция READ), то объем программы существенно уменьшится, но читабельность ее при этом ухудшится (самое интересное уйдет с экрана дисплея), а время ее выполнения изменится.

Mathcad не имеет специализированных средств, предназначенных для оптимизации программ. В «настоящих» языках программирования, вернее, в «настоящих» средах создания программ они есть.

Одно из них, называемое «profiler» (профайлер, профилировщик), позволяет провести некий хронометраж программы и выявить ее слабые места, нуждающееся в «укреплении» (в оптимизации).

Итак, поговорим о том, как Mathcad-программы можно оптимизировать.

1. Отлаживать программу можно только после ее написания, но оптимизировать программу не просто можно, но и нужно еще до открытия панели инструментов программирования (см. рис. 6.2). «Нет ничего практичнее хорошей теории!» – вот еще строка, заслуживающая быть плакатом (см. выше). Эта истина заставляет программиста искать для программы оптимальный алгоритм.

Как можно найти корень алгебраического уравнения на отрезке неопределенности a-b? Во-первых, можно разбить интервал a-b на небольшие отрезки, равные TOL (предопределенная переменная Mathcad, отвечающая за точность расчетов), и зафиксировать место, где значения функции ближе всего к засечкам на оси х – см. рис. 6.54.

Рис. 6.54. Поиск корня методом прямого перебора

Не трудно подсчитать, сколько раз в программе на рис. 6.54 вызывается функция y(x) – считать не будем, а просто скажем, что очень много. Наша тестовая функция (см. пункт 6 в главке «Отладка Mathcad-программ») простенькая и компьютер обрабатывает ее за микросекунды[93]. Но что будет, если функция сложна, отображает математические модели реального мира и работает довольно долго? Тут пригодится метод половинного деления (метод Ньютона, метод касательных и др. – см. программы 6.16-6.21). Если поиск корня методом перебора требует N вычисленных значений анализируемой функции, то метод половинного деления – всего лишь log2N.

Методом половинного деления[94] можно искать и минимум функции на отрезке a-b (рис. 6.55):

Рис. 6.55. Поиск минимума функции методом половинного деления

В программе на рис. 6.55 значение анализируемой функции в цикле высчитывается дважды – чуть левее и чуть правее середины интервала неопределенности. При реализации метода золотого сечения (рис. 6.26) для поиска минимума значение анализируемой функции в цикле высчитывается всего лишь раз, но сама программа становится несколько сложнее. Но если необходимо найти глобальный (самый минимальный) минимум полиэкстремальной функции на отрезке a-b, то ничего, кроме метода перебора, здесь не применить. Желательно при этом делить отрезок неопределенности не на равные доли, а случайно, реализуя метод случайного поиска (рис. 6.56):

Рис. 6.56. Поиск минимума функции методом случайного поиска

2. Один и тот же результат на компьютере можно получить разными путями. Но эти пути могут занимать разное время. Автор для оценки времени работы программ использует пользовательскую встроенную функцию GetTime(a). Эта функция возвращает время (в секундах), представляющее собой разницу между системным временем компьютера и значением аргумента функции GetTime[95]. Таким образом можно количественно оценить время выполнения отдельных Mathcad-операторов. С этой функцией можно проводить эксперименты и наметить некоторые пути оптимизации программ (темы лабораторных работ по программированию).

Рис. 6.57. Чистка цикла от комментария

Рис. 6.58. Замена суммы произведением

Рис. 6.59. Замена произведения возведением в целую степень

На рис. 6.57-6.59 введутся простейшие действия: числа перемножаются – число возводится в n-ю степень; числа складываются – число умножается на целочисленную константу. Результаты, как и следует ожидать, одинаковые, но время их достижения разное.

Рис. 6.60. Хронометраж вложенных циклов

На рис. 6.60 с помощью Mathcad рассчитывается сумма номеров строк и столбцов. Вывод: при организации вложенного цикла необходимо «запихивать внутрь» циклы с большим числом параметров. Дело в том, что внешний цикл организуется всего лишь раз, а внутренний – по числу значений параметра внешнего. На организацию (активизацию) цикла нужно время – отсюда и экономия.

Примем оптимизации, использованный на рис. 6.60 можно назвать постановкой матрицы «на попа»: если считать, что во внешнем цикле перебираются столбцы, а во внутреннем – строки, то формируемая матрица должна «стоять торчком» – в ней 3 столбца и 100 000 строк, а не наоборот.

Существенно ускорить работу программ можно за счет чистки циклов: «Не откладывай на завтра то, что можно сделать сегодня (послезавтра) – не делай в цикле то, что можно сделать до (после) цикла!» Из циклов (да и вообще из программ) целесообразно убрать все комментарии (у нас это текстовые константы), поместив их, например, в голове программы (см. рис. 6.57) либо правее зоны программы. Если в цикле делается ссылка на элемент вектора или матрицы и эта ссылка в цикле не меняется, то лучше этот элемент массива скопировать в скаляр до входа в цикл. Тело циклов, особенно вложенных, – это главное поле оптимизации: любая экономия здесь отзывается сторицей.

4.Разбивка программы на отдельные подпрограммы повышает ее читабельность (см., например, рис. 6.36-6.40), но одновременно увеличивает время прогонки. Отсюда вывод: в отлаженной программе для ускорения ее работы можно ссылки на подпрограммы (функции) заменить на сами подпрограммы. Особый выигрыш во времени счета достигается в программах, где ссылаются на подпрограммы (функции), записанные в других Mathcad-документах, хранимых на диске (см., например, рис. 6.49).

5. Большие массивы данных можно записывать либо в виде объемных векторов и матриц (см., например, рис. 4.10 и 4.13 в этюде 4), либо в виде файлов на диске, данные из которых считываются операторами READ и READPRN. Выбор того или иного способа хранения данных влияет и на читабельность программы и на скорость ее выполнения. Отсюда вывод, который читатель сделает для себя сам. Автор же, заканчивая эту главу, должен признаться, что три вышеотмеченных приема оптимизации Mathcad программ и другие, подобные им– это «ловля блох». По-настоящему оптимизировать программу можно, отказавшись от написания ее средствами Mathcad, и перейдя к программированию на языках не интерпретирующего, а компилирующего класса. Но при этом закроется доступ к специфическим Mathcad-функциям и операторам.



[1] В восьмой версии Mathcad новых инструментов программирования не появилось.

[2] Они остались в последующих версиях для совместимости с более ранними версиями и для тех пользователей, кто к ним привык. Правда, в мастере функций Mathcad 8 (см. рис. 1.28) функции until уже нет.

[3] На рис. 6.1 элементы векторов а и b выведены для контроля правильности решения задачи, что нередко приходится делать в целях отладки программ (см. также рис. 6.29 и 6.30, где след поиска отображен на графиках – двух- и трехмерном).

[4] Язык Mathcad, развиваясь в седьмой версии, стал все больше приобретать черты языка С. Здесь нет ничего удивительного, так как сам Mathcad писался на этом языке.

[5] VBA – Visul Basic for Applications.

[6] В Mathcad-программе поиска корня функции методом Ньютона (см. рис. 6.17) читатель может увидеть дифференциал в его общепринятом обозначении. Таким же образом в программы записываются интегралы, суммы, произведения и т.д.

[7] Первое выражение (Pascal) содержит явную синтаксическую ошибку, второе – нет, так как на языке BASIC – символ «=» означает не только присвоение, но и булеву операцию «эквивалентно». В среде языка С программист написал бы А = А == В + С, а на языке Pascal . А := А = В + С.

[8] В седьмой и восьмой версиях Mathcad оператор вывода числового значения «=» автоматически (SmarOperator) превратится в оператор присвоения «:=». Но это умолчание можно отменить.

[9] Цикл по-другому еще называют итерацией. Вот что написано в статье «Итерация» одной занимательной энциклопедии: «см. итерация».

[10] Для ускорения счета рекомендуется убирать из программ комментарии, хотя бы из тела цикла. Компилятору нужно время не только на выполнение оператора, но и на то, чтобы понять, что данный оператор выполнять не следует.

[11] Ключевые слова begin и end в среде языка Pascal отмечают начало и конец программных блоков.

[12] По TV крутятся рекламные ролики: «Нашим школам не хватает учебников. Наши детские дома требуют ремонта. Пожалуйста, заплатите налоги!» Здесь уместно будет добавить: «Пожалуйста, не воруйте бюджетные средства!»

[13] А мы знаем, что в среде Mathcad число и текст – это информация одного типа Variant. Поэтому их можно объединять в векторы и матрицы.

[14] Для этой же цели на одной строке программы мы записывали несколько операторов, разделяя их пробелами. Пробел ставится так. Сначала операторы разделяются запятыми (так было возможно разделять операторы в седьмой версии Mathcad), а потом запятые стираются. При этом появляются круглые скобки, которые можно оставить, а можно убрать. Размещение нескольких операторов на одной программной строке, как и комментирование программ текстовыми константами – это недокументированные приемы, поэтому их по возможности лучше не применять (см. также рис. 6.26). Даже вне программ нужно стараться размещать операторы столбиком. Иначе пользователь Mathcad (особенно начинающий) часто будет сталкиваться с ошибкой размещения следующего оператора чуть-чуть выше предыдущего, что нарушает причинно-следственную связь.

[15] Такую задачу в свое время успешно решал на языке BASIC К.Лапинг (рубрика «Человек и компьютер» журнала «Наука и жизнь»), которую автор в свое время редактировал вместе с Ю.В.Пухначевым.

[16] В период между Рождеством и Крещением. Программа на рис. 6.9 написана автором (вернее, подправлена для Mathcad 8) 11 января 1998 года. Так что здесь все в порядке.

[17] Здесь более уместен цикл с постпроверкой, но его нет в среде Mathcad.

[18] До Mathcad 7 Pro их тип был вещественный и при необходимости комплексный. В седьмой и восьмой версиях тип переменных – Variant (помесь числа с текстом), если исходить из стандарта языка Visual Basic и технологии OLE.

[19] Слово Pro (professional) фигурирует в названии самой современной версии Mathcad – Mathcad 8 Pro. Но в нашем контексте (см. выше) оно является латинским словом «за». Хотя слово Pro в названии пакета можно считать и некой агитацией в пользу Mathcad.

[20] Такое было возможно в ранних версиях языка BASIC, где допускались длинные переменные, но они идентифицировались только по двум первым символам.

[21] Некоторые полагают, что лет через 10-20 мы перейдем к написанию русских текстов латиницей: sejchas tak pishut teksty mejdunarodnych telegram. Молдавия, Азербайджан и некоторые другие страны СНГ уже перешли от кириллицы к латинице. Основная причина в сфере информатики. Вспомним, какие абракадабры нередко приходят к нам по e-mail.

[22] У алхимиков есть символ: «Змея, глотающая свой хвост», который подходит и для рекурсии – маленькая программа, заглатывающая память компьютера.

[23] Автор зкладывает в книгу ошибку 2000-го года: если описанному правилу будет следовать читатель в 2001 году, например, то он неверно вычислит значение данной константы – 2.719.

[24] Кстати говоря, факториал отрицательных чисел не такая уж полная чушь. У факториала (оператор целочисленного неотрицательного операнда) есть вещественный «родственник» – гамма-функция (она есть в среде Mathcad), которая работает и с отрицательными нецелыми аргументами. Значение гамма-функции при целых отрицательных значениях «улетают» в плюс-минус бесконечность.

[25] Тема чисел Фибоначчи неисчерпаема. В США даже издается специальный журнал «Fibonacci Quarterly» (электронная версия: http://www.math.uga.edu/~andrew/Fibonacci/fibauthor.html).

[26] Тройки и семерки, как автор уже отмечал неоднократно, пронизывают Mathcad.

[27] Увлекающимся числовыми последовательностями можно рекомендовать через Internet зайти на сайт www.research.att.com/~njas/sequences и воспользоваться функцией lookup. После этого можно вводить фрагмент любой взбредшей в голову числовой последовательности и ждать ответа – вариантов продолжения этой последовательности, правда, только односторонних.

[28] Еще один «долгожитель», иллюстрирующий рекурсию в книгах по программированию.

[29] Подобные задания получают студенты автора, желающие досрочно сдать экзамен по «Информатике».

[30] Слегка косят две наши милые современницы – актрисы Татьяна Шмыга и Людмила Максакова.

[31] Который, например, что-то «позаимствовал» у другого программиста, но не признается в этом даже в суде.

[32] Если единицы физических величин не используются, то нужно их совсем отключить (окно Unit System, вызываемое командой Options в меню Math).

[33] У слова «догма» есть не только отрицательный, но и положительный оттенок. Без догм не обойтись в процессе воспитания и обучения.

[34] Можно использовать и другой критерий завершения цикла: значение анализируемой функции становится меньше значения заданной точности. Так было сделано в документе на рис. 6.1 и так задумано в стандартной функции root (см. рис. 3.1).

[35] В программу на рис. 6.18 вместо «безоперандного» оператора break можно вставить оператор return, что позволит убрать последнюю строку программы с указанием локальной переменной, чье значение программой возвращается. Хотя переменную можно убрать и в программе на рис. 6.18 с оператором break. Но есть хорошее правило, не полагаясь на умолчание (программа Mathcad всегда возвращает значение последнего присваивания), дополнительно фиксировать имя возвращаемой переменной (сравните окончания программ на рис 6.17 и 6.18).

[36] Программистам-ортодоксам, раз и навсегда исключившим метку из своего арсенала, можно посоветовать наложить на себя еще одну епитимью – писать программы без использования оператора if, опираясь только на цикл while и помня, что альтернатива с одним плечом – это цикл, тело которого выполняется либо раз, либо ни разу. Предлагаем читателю для начала исключить оператор if из программ этой книги. Пример – рис. 6.20 и 6.21.

[37] Многие программисты причисляют к основным структурным управляющим конструкциям и вызов функции, особенно, рекурсивный: числа Фибоначчи без рекурсии подсчитать можно (рис. 6.11), а числа Аккермана (рис. 6.13) – затруднительно.

[38] Метод последовательных приближений широко используется в инженерных расчетах. Если блок операторов, по которым рассчитывается новое приближение, объемный, то можно рекомендовать «опустить» оператор задания первого (предыдущего) приближения к оператору вывода значения очередного приближения, записав там Ответ≡50 (если говорить о программе на рис. 5.22). Это исключит «ползанье» по Mathcad-документу.

[39] Структурная революция началась со статьи Э. Дейкстры «Programming without GOTO». Сейчас многие программисты-снобы, как нами уже отмечено, хвастают тем, что они написали не одну сотню программ, ни разу не обратившись к метке.

[40] В языке Visual Basic оператора Print тоже нет, а есть метод Print.

[41] Программы на рис. 6.26 и 6.27 были написаны для Mathcad 7, где не было средств оптимизации.

[42] Предполагается, что анализируемая функция y(x) на отрезке a-b непрерывна и имеет один минимум – представим себе веревку, протянутую между двух столбов. Оптимизация такой функции – типичная инженерная задача. Пример: самолет имеет минимальную (взлет и посадка) и максимальную скорость полета (рывок перехватчика); между ними «провисает» крейсерская скорость с минимальным расходом горючего на километр пути.

[43] Вернее, возвращает среднее арифметическое от a и b, когда отрезок между ними становится меньше TOL и одновременно накрывает точку минимума.

[44] Их четыре в двухмерной задаче, 6 в трехмерной и т.д.

[45] Первоапрельский выпуск (1997 г.) еженедельника «КомпьюТерра», который назывался «КомпьюМорра».

[46] Здесь записано ORIGIN, а не просто 0 (нуль) для того, чтобы не быть привязанным к текущему значению системной переменной ORIGIN.

[47] Попытка продлить шутку.

[48] Если иметь в виду плановое хозяйство, то «выделено».

[49] Подобные задачи мы решали в этюде 3.

[50] Хорошее правило: никогда не оставляйте в теле цикла с параметром один оператор, дополняйте его хотя бы комментарием, чтобы зафиксировать начало и конец блока операторов, составляющих тело цикла.

[51] Автор оставлял на работе включенный компьютер на выходные, а в понедельник утром считывал результат прогонки модели при N:= 1000000.

[52] Смотри ссылку в конце рис. 6.38; кроме того, эта задача есть в сборнике задач по программированию для школьников.

[53] Вариант для дам: дуэлянты стреляют не пулями, а шариками с краской. Есть такая игра под названием Paintball («красящий шарик») – участники носятся друг за другом со специальными пистолетами, оставляющими яркие пятна на одежде соперника.

[54] Многие исследователи сетуют на то, что компьютер, обрабатывая эксперимент, отдаляет (и даже отделяет) их от объекта исследования.

[55] Причин, почему у современных медицинских термометров на жидкокристаллический дисплей по-прежнему выводятся не слова, а числа, несколько. Главная, по-видимому, в том, что цифры во все времена были и будут вне языкового Вавилона прошлого и современного мира (информационное эсперанто) – они понятны и европейцу, и китайцу, и арабу независимо от их образовательного уровня. Но тот же европеец, китаец или араб, глядя на термометр, видит не цифры, а диапазоны: нормальная, повышенная и т.д.

[56] Пример нечеткого множества, кочующий из одного учебника по ТНМ в другой.

[57] Эта «анафема» коснулась и Mathcad, в среде которого метки нет (см. выше).

[58] Узкое и длинное ведро будет при носке волочиться по земле, а широкое – задевать за ногу. Понятия «удобно» нет в классической математике, но в ТНМ оно узаконено.

[59] Норма – это тоже из области теории нечетких множеств. Кто-нибудь по-настоящему задумывался, почему нормальное распределение называется нормальным?

[60] Их при желании можно создать – см. этюд 3.

[61] Она похожа на перевернутое и слегка помятое пожарное ведро.

[62] Здесь учитывается удобство уже не потребителя, а производителя пожарных ведер – круглая заготовка раскраивается без обрезков.

[63] В конце аллеи участка, где расположена дача автора, стоит пожарный щит. После определения параметров оптимального пожарного ведра автор не поленился – взял в руки линейку и пошел обмерить реальное пожарное ведро на щите. Но ведро, как и все остальное (топор, лом, багор и пр.) оказалось нарисованным на щите (виртуальный пожарный щит – «отмазка» от пожарной инспекции – в каморке папы Карло висел подобный котелок над очагом).

[64] Автор не устает повторять своим студентам, что в реальной жизни есть два нечетких множества: множество вакантных мест на рынке труда и множество людей, ищущих работу. Говоря языком математики, можно сказать, что эти множества пересекаются, но отнюдь не совпадают. Цель образования, кроме, конечно, получения удовольствия (см. комментарии к рис. 6.9), – это процесс попадания в область пересечения данных множеств.

[65] В этюде 3 на рис. 3.6 мы нарисовали что-то подобное – черный круг точек, случайно и равномерно расположенных в квадрате. В квадрат можно было «кидать» точки по иному закону распределения, например по нормальному. Так можно визуализировать нечеткое множество.

[66] Эксперимент не совсем чист – женщинам приходится вынашивать, рожать и воспитывать детей, что, конечно, отвлекает от научного и художественного творчества.

[67] Более-менее «приличные» дамские романы («Сага о Форсайтах», «Анна Каренина» и др.) написаны, кстати, мужчинами – Джоном Голсуорси и Львом Толстым.

[68] В момент завершения работы над этой книгой в продаже появился «черный» лазерный диск «Mathcad 8 Pro с документацией на русском языке». Но это был двойной обман: а) на диске была, естественно, ворованная копия Mathcad и б) документацией оказалась отсканированная или украденная в издательстве мягкая копия книги В.П.Дьяконова по Mathcad 7.

[69] Говорят, что играть на фортепьяно очень просто. Достаточно нажимать нужную клавишу в нужное время. Мы это подчеркнули еще в этюде 3, когда обсуждали «художества» на компьютере. Гениальных же пианистов единицы потому, что Создатель не в силах обслужить всех играющих. Проблемы трудолюбия музыканта (программиста) мы касаться не будем, отсылая читателя к «Моцарту и Сальери» Пушкина, где эта тема разработана достаточно глубоко.

[70] В английском языке нет такой путаницы – там пишут Copyright – права на копирование. У нас же этот термин переводят неправильно – «авторские права».

[71] Здесь могут быть не потери, а прибыли. Тот же автор, написав новый труд, может получить за него гораздо больше, если он известен в читающем мире не в последнюю очередь и через нелегальные копии. Примеры: Булгаков, Высоцкий, Пастернак, Бродский… Последние двое вряд ли получили бы Нобелевские премии, если б их в свое время издали массовыми тиражами.

[72] О великий и могучий!.. В одном предложении семь аббревиатур, но иначе не скажешь.

[73] Можно дать голову на отсечение, что у писавших обличительные статьи на компьютере хоть одна из программ (DOS-Windows-Word или DOS-Лексикон) стоит нелегально. Многие милицейские отделения оборудованы компьютерами (документация, базы данных и т.д. и т.п.), но опять же можно дать что угодно на отсечение, что ни в одном отделении, включая и то, из которого был организован рейд на компьютерные рынки, вы не увидите коробок с легальными версиями программ. Милицейские чины часто по телевизору комментируют криминальную сводку. На втором плане, как правило, компьютер – тоже, мол, не лыком шиты. На экране – две голубые панели NC. Ворованные, кстати говоря.

[74] Знаменитый московский рынок черного софта.

[75] В магазине концерна «Белый ветер» на Никольской улице в Москве висит плакат: татуированная рука накрывает мышку компьютера, а сверху надпись: «Не воруй!» Автор прошелся по магазину и посмотрел цены на ноутбуки (специализация концерна). Так вот, если надбавка к цене составляет 20-30%, то ее называют торговой, а если 200-300%, то – бандитской. На Западе цена самого дорогого ноутбука 2500 долларов. Дороже может стоить только какой-нибудь спецзаказ с перламутровыми клавишами. Купить ноутбук за 5000 «косых» да еще и полное программное обеспечение к нему может только тот, чья рука изображена на плакате, смысл которого после экскурсии по магазину меняется.

[76] Упоминавшееся московское отделение знаменитой фирмы, с одной стороны, борется с пиратством, а с другой – его косвенно поощряет. Один коллега автора купил там для фирмы, где он «халтурит», легальную копию офисной системы за 2500 долл., хотя на лотках ее продают за 90 рублей. При установке программы понадобилась консультация. Звонят продавцу, а он отвечает, что перепоручил послепродажную поддержку программы другой фирме. Звонят туда. А там отвечают, что у них консультации платные – 60 долл. за вопрос. За такие деньги они консультируют, естественно, всех подряд, а не только легальных пользователей.

[77] Сексуальный аспект проблемы, если хотите.

[78] Аналогия здесь и в том, что и тот и другой мешают жене и мужу (программе и пользователю). Настоящим же пиратам все нипочем – и пояс верности, и электронный ключ ломаются довольно просто. Еще одна параллель: беспорядочный секс и нелегальное копирование программ – это главный путь распространения вирусов, человеческих и компьютерных.

[79] В городе Переславле Залесском когда-то собрались деятели ИТ-индустрии, поклялись не работать больше с черным софтом и призвали других поступать также.

[80] Читаем у Достоевского: «Был  он  и  честен,  то есть ему не пришлось сделать чего-нибудь особенно бесчестного…» (http://lib.ru/LITRA/DOSTOEWSKIJ/anekdot.txt).

[81] См. главку «Как автор продавал программы» в этюде 3.

[82] Автор познакомился с такой практикой, учась (хорошему и плохому) в Германии. Там нередко ставят программу одной установки на много машин, но одновременно просят на это разрешение фирмы-изготовителя. Фирма дает на это добро, идя навстречу университету (где еще можно так успешно рекламировать свою продукцию) и понимая, что в случае отказа программы все равно поставят.

[83] Как сказать. Этот этюд самый объемный в книге. К помощи Mathcad часто обращаются те, кто не может или не хочет работать с чистыми языками программирования. Но постепенно эти люди втягиваются в программирование в среде Mathcad и по необходимости переходят к «серьезным» языкам.

[84] Можно только предположить, что отладчик фирма MathSoft приберегает для «этапной» версии Mathcad – Mathcad 2000. Сейчас как из рога изобилия посыпятся программные продукты с приставкой «2000».

[85] Здесь мы отказались от обрамления отдельных операторов серым фоном.

[86] Принцип «Щелкни кобылку по носу – она махнет хвостом».

[87] Что с успехом делают студенты автора при курсовом и дипломном проектировании.

[88] С точки зрения чистой математики действительных значений даже в узком диапазоне неограниченное количество. В среде Mathcad и в других программных средах действительных значений переменных конечное число.

[89] У фанатов языка APL (у «апиэльщиков») есть неписаное правило – программа должна полностью умещаться на экране дисплея.

[90] Считается, что подпрограмма – это припев песни, который поют несколько раз, а в текстах песен печатают только один раз. Но отдельный элемент программы целесообразно выделить в отдельную процедуру даже в том случае, когда этот элемент работает всего лишь раз. Во-первых, так удобнее отлаживать программу, а во-вторых, эту процедуру можно вызывать из других программ.

[91] Автор при тестировании бета-версий Mathcad просил разработчиков ввести в систему жесткий запрет на переопределение встроенных функций и констант (встроенные операторы, кстати, переопределять нельзя), но это не было сделано.

[92] Из них можно сделать заставку для экрана дисплея, появляющуюся перед глазами пользователя, когда он на время задумывается и не касается клавиш компьютера.

[93] Водительское определение микросекунды: это время, прошедшее с момента появления зеленого света светофора до подачи звукового сигнала водителем, сидящим в задней машине. Микросекунда здесь не 10-6 с, а элемент нечеткого множества «очень быстро».

[94] Метод половинного деления – это универсальный метод численного решения задач. Вот его «зоологическая» интерпретация: «Как поймать льва в пустыне? Нужно ее оградить забором, перегородить пополам и посмотреть, где оказался лев. Эту половинку пустыни перегородить еще раз. Так поступать до тех пор, пока (оператор while) лев не окажется в ящике, размером TOL

[95] Эту функцию и описание ее создания можно «скачать» из ftp-сервера ftp:\\twt.mpei.ac.ru\ochkov\mathcad и поместить в подкаталог userefi каталога Mathcad. После этого ссылка на нее появится в окне вставки функций (рис. 1.28).